Monday, August 5, 2013

Revenue Recognition

Revenue Recognition principle is one of the important principles of Accrual Accounting. According to this principle, revenue must be recognized when
(1) They are realized or realizable and
(2) They are earned
Revenue is realized when products are exchanged for cash or claims to cash (Receivable).
Revenue is realizable when related assets received are readily convertible to cash or claims to cash.
Revenue is earned when the products are delivered or services are performed.
Recognizing the revenue means recording the amount as revenue in the financial statements.
Realization is the process of converting non-cash resources into cash.
In the Revenue Recognition principle, it does not matter when cash is received. (In Cash Basis Accounting, revenue is recognized when cash is received no matter when goods or services are sold).
For revenue to be recognized, both the above conditions must be met. In other words for revenue to be recognized, final delivery must be completed (of goods or services) and there has to be a payment assurance.
Let us have a look at the timing of Revenue Recognition
1) For sale of finished goods (Inventory Items), revenue is recognized at the date of sale (some interpret this as the date of shipping or the date of delivery)
2) For sale of services (e.g. support services), revenue is recognized when the services are performed (delivered)
3) For sale of Asset Items (other than inventory items like finished goods), revenue is recognized at the point of sale (i.e. when the customer is invoiced)
4) For revenue from other activities like rent for using company’s Fixed Assets, revenue is recognized as time passes or as assets are used.
Examples:
1) If a company invoices its customer for 100 units of item ‘A’, and ships (delivers) only 25 units, the company cannot recognize revenue for entire 100 items. It can only recognize revenue equivalent to the number of units delivered (Revenue is earned only when the products are delivered). Similarly, let’s say you pay $120 in advance to company ‘ABC’ for magazine subscription for one full year. The fact that company ‘ABC’ received money for one full year does not mean that they can record the entire amount as Revenue. In-fact the amount received in advance is a Liability to the company because they have to deliver magazines to their customer every month and if they fail to do so, they are liable to refund the amount received in advance. In this scenario, the company will recognize 1/12th of the entire amount every month as earned revenue after they deliver the magazine.
2) Company ‘ZXC’ signs a 3 year support contract with its client for a total amount of 3 million. This amount cannot be recorded as revenue unless the Company provides the support services to the client. Assuming the company is following a monthly calendar accounting period, the company will recognize 1/36th of the entire support contract deal amount every month. (Revenue is recognized when services are performed)
There are few exceptions to the timing of revenue recognition for sale of inventory items. Under normal scenario, revenue is recognizes at the point of sale, however if there are return policies, and if the company cannot reasonably estimate the amount of future returns, the revenue should be recognized only after the expiration of the return policy period.
Revenue Recognition Accounting:
If revenue is not recognized immediately, what is the accounting entry for the Sales Invoice? Let’s have a look
Let’s say, you invoice the Customer in Advance for the annual support contract of $12000. Since, you are invoicing the customer in Advance, you debit your Receivables. But then if you are not crediting the revenue right away, where do you account for the credit side of the accounting entry? You credit, what is called as Deferred Revenue (or Unearned Revenue). Deferred Revenue is actually a liability for the company. (The company is liable to provide the goods or services for which cash is received or will be received in advance). As and when the goods or services are delivered, the Deferred Revenue is reduced (debited) and revenue is recognized.
Accounting when the Invoice is created in Jan
Date
Accounting Class
Debit
Credit
Comments
1-Jan
Receivables
12000

The entire receivables is recognized in advance. How this receivable is collected will depend on the payment terms of the Invoice
1-Jan
Deferred Revenue

12000


End of Jan, Revenue is recognized for 1/12th of the entire amount, because the company has provided one month’s service to its client. To that effect, Deferred Revenue will be reduced and revenue will be recognized
Date
Accounting Class
Debit
Credit
Comments
31-Jan
Deferred Revenue
1000

Deferred Revenue reduced
31-Jan
Earned Revenue

1000
Earned Revenue amount for one month

End of Feb, another months revenue is recognized
Date
Accounting Class
Debit
Credit
Comments
28-Feb
Deferred Revenue
1000

Deferred Revenue reduced
28-Feb
Earned Revenue

1000
Earned Revenue amount for one month

The company will have similar accounting entry each month till Dec. At the end of Dec, the Deferred Revenue will be Zero and the entire amount will be reported as Revenue earned.








Rules for Revenue recognition ( instead of using Accounting rules )

SOURCE

API approach
This is most flexible approach. You can find sample script of the ar_revenueadjust_pub API here and here. In this example I am deferring revenue for all the amount of the invoice for 12 months equally. If you are creating invoices all through the day (not in batch mode), you can create a subscription to a standard oracle business event oracle.apps.ar.transaction.Invoice.complete (as shown in this API). If it is in the batch mode, you can create a concurrent program and run that after invoices are created or imported but before accounting is created in Subledger Accounting to transfer to GL.




DECLARE
   x_return_status   VARCHAR2 (1);
   x_msg_count       NUMBER;
   x_msg_data        VARCHAR2 (4000);
   x_adj_id          NUMBER;
   x_adj_number      VARCHAR2 (100);
   v_msg_index_out number;
BEGIN
   mo_global.set_org_context (204, NULL, 'AR');
   fnd_global.apps_initialize (1005902, 50559, 222);
   xx_inv_complete.defer_revenue (523432, 807271, 1500, x_return_status, x_msg_count, x_msg_data, x_adj_id, x_adj_number);
    DBMS_OUTPUT.put_line ('Return Status is :' || x_return_status);
      DBMS_OUTPUT.put_line ('Msg Count is :' || x_msg_count);
      DBMS_OUTPUT.put_line ('Adjustment ID is :' || x_adj_id);
      DBMS_OUTPUT.put_line ('Adjustment Number is :' || x_adj_number);
   IF x_msg_count > 0
      THEN
         FOR v_index IN 1 .. x_msg_count
         LOOP
            fnd_msg_pub.get (p_msg_index => v_index, p_encoded => 'F', p_data => x_msg_data, p_msg_index_out => v_msg_index_out);
            DBMS_OUTPUT.put_line (x_msg_data);
            DBMS_OUTPUT.put_line ('============================================================');
         END LOOP;
      END IF;
END;






CREATE OR REPLACE PACKAGE BODY xx_inv_complete
AS
   FUNCTION inv_complete (p_subscription_guid IN RAW, p_event IN OUT NOCOPY wf_event_t)
      RETURN VARCHAR2
   IS
      CURSOR get_trx_lines (p_cust_trx_id IN NUMBER)
      IS
         SELECT customer_trx_line_id, extended_amount
           FROM ra_customer_trx_lines rci
          WHERE customer_trx_id = p_cust_trx_id;

      i                       INTEGER;
      l_key                   VARCHAR2 (240)                             := p_event.geteventkey ();
      l_payment_schedule_id   NUMBER (15);
      l_customer_trx_id       NUMBER;
      l_org_id                NUMBER;
      l_user_id               NUMBER;
      l_resp_id               NUMBER;
      l_application_id        NUMBER;
      l_security_gr_id        NUMBER;
      l_counter               NUMBER;
      l_history_exists_flag   BOOLEAN;
      l_ps_exists             BOOLEAN;
      l_history_rec           ar_trx_summary_hist%ROWTYPE;
      l_tot_inv_amt           NUMBER;
      l_inv_inst_count        NUMBER;
      l_rev_adj_rec           ar_revenue_adjustment_pvt.rev_adj_rec_type;
      v_msg_index_out         NUMBER;
      v_message               VARCHAR2 (4000);
      x_return_status         VARCHAR2 (1);
      x_msg_count             NUMBER;
      x_msg_data              VARCHAR2 (4000);
      x_adj_id                NUMBER;
      x_adj_number            VARCHAR2 (100);
      j                       NUMBER;
      l_amount                NUMBER;
      l_per                   NUMBER;
      l_gl_date               DATE;
   BEGIN
      l_customer_trx_id := p_event.getvalueforparameter ('CUSTOMER_TRX_ID');
      l_org_id := p_event.getvalueforparameter ('ORG_ID');
      l_user_id := p_event.getvalueforparameter ('USER_ID');
      l_resp_id := p_event.getvalueforparameter ('RESP_ID');
      l_application_id := p_event.getvalueforparameter ('RESP_APPL_ID');
      l_security_gr_id := p_event.getvalueforparameter ('SECURITY_GROUP_ID');
      SAVEPOINT inv_complete_event;
      fnd_global.apps_initialize (l_user_id, l_resp_id, l_application_id);

      FOR i IN get_trx_lines (l_customer_trx_id)
      LOOP
         defer_revenue (l_customer_trx_id
                      , i.customer_trx_line_id
                      , i.extended_amount
                      , x_return_status
                      , x_msg_count
                      , x_msg_data
                      , x_adj_id
                      , x_adj_number
                       );
      END LOOP;

      RETURN 'SUCCESS';
   EXCEPTION
      WHEN OTHERS
      THEN
         ROLLBACK TO inv_complete_event;
         fnd_message.set_name ('AR', 'GENERIC_MESSAGE');
         fnd_message.set_token ('GENERIC_TEXT', SQLERRM);
         fnd_msg_pub.ADD;
         wf_core.CONTEXT ('AR_BUS_EVENT_SUB_PVT'
                        , 'INV_COMPLETE'
                        , 'oracle.apps.ar.transaction.Invoice.complete'
                        , p_subscription_guid
                         );
         RETURN 'ERROR';
   END inv_complete;

   PROCEDURE defer_revenue (
      p_customer_trx_id        IN              NUMBER
    , p_customer_trx_line_id   IN              NUMBER
    , p_ext_amount             IN              NUMBER
    , x_return_status          OUT NOCOPY      VARCHAR2
    , x_msg_count              OUT NOCOPY      NUMBER
    , x_msg_data               OUT NOCOPY      VARCHAR2
    , x_adj_id                 OUT NOCOPY      NUMBER
    , x_adj_number             OUT NOCOPY      VARCHAR2
   )
   IS
      l_rev_adj_rec     ar_revenue_adjustment_pvt.rev_adj_rec_type;
      v_msg_index_out   NUMBER;
      v_message         VARCHAR2 (4000);
      j        CONSTANT NUMBER                                     := 12;
      l_amount          NUMBER;
      l_per             NUMBER;
      l_gl_date         DATE;
   BEGIN
      l_amount := (p_ext_amount / j);
      l_per := (l_amount / p_ext_amount);

      FOR i IN 0 .. j
      LOOP
         l_gl_date := SYSDATE + (i * 30);
         l_rev_adj_rec.customer_trx_id := p_customer_trx_id;
         l_rev_adj_rec.adjustment_type := 'UN';
         l_rev_adj_rec.amount_mode := 'A';
         l_rev_adj_rec.amount := l_amount;
         l_rev_adj_rec.PERCENT := l_per;
         l_rev_adj_rec.line_selection_mode := 'S';
         l_rev_adj_rec.from_cust_trx_line_id := p_customer_trx_line_id;
         l_rev_adj_rec.reason_code := 'RA';
         l_rev_adj_rec.comments := 'TEST';
         l_rev_adj_rec.gl_date := l_gl_date;
         ar_revenueadjust_pub.unearn_revenue (p_api_version            => 2.0
                                            , x_return_status          => x_return_status
                                            , x_msg_count              => x_msg_count
                                            , x_msg_data               => x_msg_data
                                            , p_rev_adj_rec            => l_rev_adj_rec
                                            , x_adjustment_id          => x_adj_id
                                            , x_adjustment_number      => x_adj_number
                                             );
         DBMS_OUTPUT.put_line ('Return Status is :' || x_return_status);
         DBMS_OUTPUT.put_line ('Msg Count is :' || x_msg_count);
         DBMS_OUTPUT.put_line ('Adjustment ID is :' || x_adj_id);
         DBMS_OUTPUT.put_line ('Adjustment Number is :' || x_adj_number);

         IF x_msg_count > 0
         THEN
            FOR v_index IN 1 .. x_msg_count
            LOOP
               fnd_msg_pub.get (p_msg_index          => v_index
                              , p_encoded            => 'F'
                              , p_data               => x_msg_data
                              , p_msg_index_out      => v_msg_index_out
                               );
               v_message := SUBSTR (x_msg_data, 1, 200);
               DBMS_OUTPUT.put_line (x_msg_data);
               DBMS_OUTPUT.put_line ('============================================================');
            END LOOP;

            DBMS_OUTPUT.put_line (SUBSTR (v_message, 1, 2000));
            DBMS_OUTPUT.put_line ('============================================================');
         END IF;
      END LOOP;
   EXCEPTION
      WHEN OTHERS
      THEN
         ROLLBACK;
         fnd_message.set_name ('AR', 'GENERIC_MESSAGE');
         fnd_message.set_token ('GENERIC_TEXT', SQLERRM);
         fnd_msg_pub.ADD;
   END defer_revenue;
END xx_inv_complete;
/

Thursday, August 1, 2013

COST Calculation + Cost Account customization

PAckages

CSTPACDP.insert_account  - this will store data in mtl_transaction_accounts.

For customization

           if (l_std_from_org <> 0) then    -- To see if there is COGS account from Hook
               l_acct := CSTPSCHK.std_get_account_id(l_from_org, p_txn_id, -1*sign(l_snd_qty), 2,
                                  l_cost_element, null, l_from_subinv, l_from_cg,
                                  0, 1, l_err_num, l_err_code, l_err_msg);
            else
      /*BUG 8206088 ADDED 'l_from_cg' */
               l_acct := CSTPACHK.get_account_id(l_from_org, p_txn_id, -1*sign(l_snd_qty), 2,
                                  l_cost_element, null, l_from_subinv,
                                  0, 1, l_err_num, l_err_code, l_err_msg,l_from_cg);
            end if;



DEFAULT COGS ACCOUNT

        SELECT nvl(MSI.cost_of_sales_account, MP.cost_of_sales_account)
        INTO l_om_ccid
        FROM mtl_system_items MSI, mtl_parameters MP
        WHERE MSI.organization_id = l_from_org
        AND   MSI.inventory_item_id = p_item_id
        AND   MP.organization_id = MSI.organization_id;

        INV_WORKFLOW.call_generate_cogs(l_rcv_coa_id, l_cust_id, p_item_id, l_header_id, l_line_id,
                     l_order_type, l_to_ou, l_inv_ccid, l_concat_seg, l_msg_data, l_to_org)



Check if item is ASSET or EXPENSE ITEM
     SELECT decode(inventory_asset_flag, 'Y', 0, 1)
     INTO l_from_exp_item
     FROM mtl_system_items_b
     WHERE organization_id = l_from_org
     AND inventory_item_id = p_item_id;


-------------------------------------------------------------------------------------------------------

CSTPACHK, procedure actual_cost_hook is function called from Oracle standard package CSTPAVCP which use to process all material transactions.

         -- If the sending org is standard costing, get costs from CIC, otherwise from MCACD
         if (l_std_from_org <> 0) then
            l_stmt_num := 190;

            /* Bug 3239084: use cst_item_cost_details from the costing org to support cost sharing */
            SELECT sum(item_cost)
            INTO l_elem_cost
            FROM cst_item_cost_details
            WHERE inventory_item_id = p_item_id
            AND   cost_element_id = l_cost_element
            AND   cost_type_id = 1
            AND   organization_id =
                  (select cost_organization_id
                   from mtl_parameters
                   where organization_id = l_from_org);
         else
            l_stmt_num := 200;

            SELECT layer_id
            INTO l_from_layer
            FROM cst_quantity_layers
            WHERE inventory_item_id = p_item_id
            AND organization_id = l_from_org
            AND cost_group_id = l_from_cg;

            l_stmt_num := 210;

            SELECT sum(actual_cost)
            INTO l_elem_cost
            FROM mtl_cst_actual_cost_details
            WHERE transaction_id = p_txn_id
            AND organization_id = l_from_org
            AND cost_element_id = l_cost_element
            AND layer_id = l_from_layer;
         end if;

Standard v/s AVG Costing


You can have different cost method for each inventory org. 
Be careful that Oracle does not support changing cost method once items are enabled

you can enable standard costing in master and average cost in inventory orgs. So transactions occur at avg cost. But this will enable you compare or do various analysis if needed with reports using standard cost in master.

 
Standard Costing
 
Average Costing
 
Material and material overhead with Inventory; all cost elements with Bills of Material
Material with Inventory; all cost elements with Bills of Material
Item costs held by cost sub-element
Item costs held by cost element
Unlimited sub-elements
Unlimited sub-elements
Can share costs across organizations.  The master cost organization can be the only organization using WIP.
No shared costs; average cost is maintained separately in each organization
Moving average cost is not maintained
Maintains the average unit cost with each transaction
Separate valuation accounts for each subinventory and cost element
Separate valuation accounts for each cost element (see note below)
Variances for WIP transactions
No variances for WIP transactions

*The average unit cost is maintained at the organization level.  If you had separate valuation accounts by subinventory, total inventories would balance, but account balances by subinventory would not match the inventory valuation reports.


STANDARD COSTING
------------------------------

Accounting principles require inventory to be valued at actual cost. To make things easy, standard costs are often set to approximate actual costs and have inefficiencies built in. Variances to standard are then capitalized and amortized over estimated inventory turns. Alternatively standard costs are built to measure performance efficiency and set performance targets. It provides the ability to measure performance.

Standard costing is mostly applicable for process manufacturing & industries.

Standard costing is opted If the cost of raw material for manufacturing the finished good is going to be consistent for a given period of time say during a financial year and there are not many fluctuations are expected in their cost

In this scenario, standard costs are established and the actual performance is measured against those standards by way of variance analysis. 

Standard costing has a lot of ideal quantitative parameters like BOM, process time, process wastage, machine and labour hours consumed, batch sizes etc.

At the end of month we only need to adjust the differences by variance Analysis.
You must have a great database to develop great variance analysis reports.
Without an ERP/MRP, variance analysis using standard costing is very challenging, specially where there are several processes and items cannot be standardized.

Operations team could vary the batch sizes due to other parameters like production optimisation, raw material flow issues, machine down time etc. As a result the variances between standard costing and actual costing could consistently vary either +/- making the variance analysis a mere number crunching exercise. Unless the operations are standardised taking into account all operational issues, standard costing may not work. 
In setting standards, you are creating benchmark for operations, where you have starting point for understanding variances, thus, good for cost control. You have to fine-tune your standards to reflect what is practical and achievable. Preparing budgets, identifying BEP and analyzing cost-volume-profit analysis will be handy with standard costing.


Standard costing has a lot of advantages especially in the manufacturing process where the company can use the STD COST as a type of good internal competitivity between Manufacturing X Commercial área. according to the improvents in the production operation, Manufacturing is engaged to reduce costs and improve processes to help increasing the margins and adding value to the company. The main challenge is the discussion of the level of standard costs, what needs to be consider Market price, competitiveness and several other points.

As in any system the goal is to determine what cost assumptions I made up front have changed, for whatever reason, and what levers can I pull to address, either with the customer, supplier or my own process. The goal is always to measure against the plan and the plan is always standard cost unless you are working in a Cost Plus contract environment.

If you not measuring your standard variances on a monthly 
basis then having standards set up is a waste of time both to engineering and  accounting. 
Standard costing is easy to manage but, needs to dive deeply into more analytical procedures at incrption & on regular basis to monitor the mood of production cycle.

The std cost process finalized to obtain a fine set of reports is an important goal that you have to pursue. But this is the first step to pull more and more your firm to an efficiency process. Many times (not always, unfortunately) std cost represents a way to evaluate the real cost of your production, through which the management could decide to define the sales price. In this way, the sales price could be properly fixed or not. I would be more calm, working on sales price, if i knew that the assembly process is efficient. Std cost, infact, could drive (in a right or wrong way) the process of Sales Price definition

standard costing and variance analysis can be applied not only for material cost but also for labour & overheads. If your company has done a work study of the jobs involved and arrived at a standard labour hour for assembling valves of different types you can calculate the standard cost of labour per valve (standard hours required to complete one assembly x standard labour hour rate). Please note that you can build in normal process idle time so that the standard hour is set properly. In order to do this you need to break down the entire assembly activity into sub-activities for calculate std hour for an efficient and a not so efficient employ. You may then take a weighted average if you have a mix of efficient and not so efficient employees (ignore extremes on either side). After the standard labour cost is worked out, you can do variance analysis for labour cost as usual.
using the resulting labor efficiency for one of your KPI's. This is achieved by calculating what your labor hours 'should' have come in at based on quantity produced x std labor cost and dividing by your actual direct labor hours. This can be done at designated departments or sub-component level. This enable you to keep a close eye on performance throughout the process as well as highlight when efficiencies have improved to the point where your standards needs to be adjusted. 


I've found the most efficient method for the finance department is using standard cost. I've set up cost reserves to capitalize any variances as a separate account from the valuation at standard. This enables a quick reconciliation of accounts and using standards provides the ability to measure performance. This is very efficient for the finance department but can be a challenge in times of extreme cost fluctuations since may "canned" reports will used your chosen valuation method to determine product margins. Knowing your current product costs is critical for capturing true margins for many decision making exercises.


The capitalization of variances (all variances, not just overhead) can be done locally or at corporate. In a very large organization, it makes sense to capitalize at corporate since many variances will offset by the time they reach the top. On the consolidated P&L, the capitalized variances are taken to P&L over the turn of the inventory to be GAAP compliant.

Lately I've used direct cost. All labor and overhead costs are calculated on the balance sheet as two lines: Variable Costs in Inventory or Period Costs in Inventory and are recalculated and updated every quarter. It's clean, easy and GAAP compliant. Standard costs are only updated once a year unless there is a significant cost change event.


STANDARD COSTING does not work where always.

Unless the operations are standardized taking into account all operational issues, standard costing may not work.
Price variations happen all the time in all industries but within a range. Where the fluctuations are beyond the normal economic theories, standard costing could fail.


AVERAGE COSTING
-------------------------------

Average costs can not be shared across inventory organizations.

But average costing is typically for purchasing environment, and don't allow you to maintain cost in detail by cost elements. Average costing does not book any variances

If you know that the cost of raw material is fluctuating and there is no consistency in it, it is suggested to go for average costing method.

You need not recognize PPV (purchase price Variance )

Weighted Average is an option is you revaluate your inventories every month or quarter and your purchases are been acquired for several vendors and the price is different for each of them. 

BUT *****
but if you are in a business that is experiencing a lot of fluctuations in raw materials you can get stung very quickly using average costing. Also, it limits your ability to give your sales group accurate current cost information for bidding/quoting purposes. 


WHEN parts prices vary frequently Average costing  keeps our costs 'current' - No need to do massive Standard Cost updates to items (we have 100k items so that would be a ton of work!!) 

DISADVANTAGES

 Use of 'generic' part numbers for purchasing can make costs charged to a sale be very different from PO price when different items are ordered using the same part number and they have widely different prices

The key drawback to average costing is that it is just a 'Mathematical Exercise' and hence do not provide you help with any analysis. Also, if you are a bulk purchaser and your purchases are few and far between, the mathematical average will be significantly different from the 'Current Cost'. Another disadvantage is that it is a 'Post Facto' costing and hence not much help for any pre-emptive analysis. 


Misc receipt without putting proper cost could really mess up your average cost quickly. 

If your org allows negative, be careful on how it affects average cost calculation.

Only downside we have with Average is that you cannot have multiple accounts (ie - material, overhead) for different subinventories. Same accounts for all.




----------------------------

We are in process of converting a Standard Cost Org to Average. We are essentially: 
1) Renaming the original Org (ie XX-
2) Copy Org to new 
3) Update scripts for Costing Method and Subinventory Accounts (because once you copy you can't change Costing Method 
By all accounts, it seems to be testing out fine. We did run into some issues with invalid accounts on items, but that was purely a data issue on our part. 

Thursday, July 11, 2013

ROI - How To Perform. Receipt On Internal Requisition / Internal Sales Order Via Receiving Open Interface? [ID 365200.1]

ROI - How To Perform. Receipt On Internal Requisition / Internal Sales Order Via Receiving Open Interface? [ID 365200.1] (come from metalink)
Applies to:
Oracle Inventory Management - Version: 11.5.1 to 12.1.3 - Release: 11.5 to 12.1
Information in this document applies to any platform.
EXECUTABLE:RVCTP - Receiving Transaction Processor
Goal
How to enter a Receipt (Receive/Deliver Transactions) for an Internal Requisition / Internal Sales Order via the Receiving Open Interface?
New functionality of 11.5.10/11i.SCM_PF.J/11i.PRC_PF.J (and higher) is ROI supports for Internal Order
. RECEIVE transaction
. DELIVER transaction

Solution
Following SAMPLE script. is intended to enter a Receive and Deliver to Inventory Transaction with Inventory destination type for an Internal Sales Order between 2 inventory organizations with Direct Receipt Routing through the Receiving Open Interface (ROI)
(ie Perform. the RECEIVE and DELIVER transaction at the same time)
The script. will load records into the tables
•RCV_HEADERS_INTERFACE,
•RCV_TRANSACTIONS_INTERFACE,
If the item is a lot or serial controlled standard item, records must also be inserted into
MTL_TRANSACTION_LOTS_INTERFACE and MTL_SERIAL_NUMBERS_INTERFACE tables.
SETUP
0) In release 11.5.10 Ensure to apply the patches listed in Note 367396.1- Recommended Patches for Enhanced Receiving Validation after upgrade to or install of 11.5.10 (or 11i.SCM_PF.J)
For Release 12 see Note 423541.1 
1) Inventory Setup: Organizations/Shipping Networks
from Sending Organization Org1 D2 Miami to Destination Organization Org2 M2 Boston
Transfer Type=Intransit
Receipt Routing=Direct
2) Miscellaneous Account receipt in org D2 On subinventory FGI for a quantity =500
has been entered on item AS54888
Item AS54888 is a standard item - Not a lot and serial controlled Item
SQL> Select mp.organization_id Org_Id, mp.organization_code Org_Code,
msi.inventory_item_id, msi.segment1, decode(to_char(msi.lot_control_code),
'2','Y',
'1','N') LOT_CONTROL,
decode(to_char(msi.serial_number_control_code),
'1','None',
'2','Predefined',
'5','Dynamic at INV receipt',
'6','Dynamic at SO issue') SERIAL_CONTROL
from mtl_system_items_b msi,mtl_parameters mp
where msi.segment1 like 'item' and msi.organization_id=mp.organization_id;
It returns LOT_CONTROL='N' and SERIAL_CONTROL='None'
inventory_item_id=149 for item=AS54888
3) In Purchasing responsibility
. Enter and approve Internal requisition number 5709
One line for inventory item AS54888 quantity=10 UOM=Each
with
Destination rganization=M2 Boston
Destination location= M2- Boston
Source=Inventory
Source rganization=D2 Miami
Source Subinventory=FGI
. Run the Create Internal Orders program to interface the Internal item to OM

4) In Order Management Responsibility, process the Internal Sales Order:
. Run Order Import concurrent program. (OEOIMP module: Order Import)
. Orders, Returns/Order Organizer
For Internal Requisition 5709 Internal Sales Order number 56753 has been created and booked
. Shipping/Release Sales Orders
Release the sales order 56753
. Shipping Transactions
1 Line related to delivery = 64883
Line status = Staged/Pick Confirmed
. Shipping/Ship Confirm Deliveries SRS
Run the program for Delivery = 64883
. Ensure to run WSHINTERFACE module: Interface Trip Stop
. Shipping / Transactions - For ISO Sales Order 56753
Line Status=Interfaced
Delivery status=Closed
5) In Purchasing Responsibility
Receiving/Receipts
In org M2 Boston
Find expected receipts
Source Type =Internal
Requisition = 5709
- Ensure 1 line is available to be receipted
Order type= Internal Order
Order =64883
(= Shipment Number = Delivery name of Internal Sales order 56753)
6) Run the following scripts so to find the necessary information to insert into the RCV_HEADERS_INTERFACE and RCV_TRANSACTIONS_INTERFACE table
Receipt of internal Requisition Number 5709
6.1) SQL> Select rh.*
from po_requisition_headers_all rh
where segment1 like 'InternaReqNumber';
REQUISITION_HEADER_ID=56678
SEGMENT1=5709
TYPE_LOOKUP_CODE=INTERNAL
ORG_ID=204
6.2) SQL> Select rl.*
from po_requisition_lines_all rl,
po_requisition_headers_all rh
where rh.requisition_header_id = rl.requisition_header_id
and rh.requisition_header_id =ReqHeaderId;
REQUISITION_LINE_ID=60678
REQUISITION_HEADER_ID=56678
CATEGORY_ID=91
UNIT_MEAS_LOOKUP_CODE=Each
QUANTITY=10
DELIVER_TO_LOCATION_ID=209
TO_PERSON_ID=13536
SOURCE_TYPE_CODE=INVENTORY
ITEM_ID=149
QUANTITY_DELIVERED=0
SOURCE_ORGANIZATION_ID=210
DESTINATION_TYPE_CODE=INVENTORY
DESTINATION_ORGANIZATION_ID=209
ORG_ID=204
6.3) SQL> Select rsh.*
from rcv_shipment_headers rsh,
rcv_shipment_lines rsl,
po_requisition_lines_all rl
where rsl.shipment_header_id = rsh.shipment_header_id
and rsl.requisition_line_id = rl.requisition_line_id
and rl.requisition_line_id =RequisitionLineId;
SHIPMENT_HEADER_ID=59417
RECEIPT_SOURCE_CODE=INTERNAL ORDER
ORGANIZATION_ID=210
SHIPMENT_NUM=64883
SHIP_TO_LOCATION_ID=209
SHIP_TO_ORG_ID=209
6.4) SQL> Select rsl.*
from rcv_shipment_lines rsl,
po_requisition_lines_all rl
where rsl.requisition_line_id = rl.requisition_line_id
and rl.requisition_line_id =RequisitionLineId;
SHIPMENT_LINE_ID=66367
SHIPMENT_HEADER_ID=59417
LINE_NUM=1
CATEGORY_ID=91
QUANTITY_SHIPPED=10
QUANTITY_RECEIVED=0
UNIT_OF_MEASURE=Each
ITEM_DESCRIPTION=Sentinel Standard Desktop
ITEM_ID=149
SHIPMENT_LINE_STATUS_CODE=EXPECTED
SOURCE_DOCUMENT_CODE=REQ
REQUISITION_LINE_ID=60678
REQ_DISTRIBUTION_ID=59631
ROUTING_HEADER_ID=3
FROM_ORGANIZATION_ID=210
DELIVER_TO_PERSON_ID=13536
DESTINATION_TYPE_CODE=INVENTORY
TO_ORGANIZATION_ID=209
DELIVER_TO_LOCATION_ID=209
SHIP_TO_LOCATION_ID=209
OE_ORDER_HEADER_ID=null
OE_ORDER_LINE_ID=null
AMOUNT_RECEIVED=0
6.5) SQL> Select ms.*
from mtl_supply ms,
po_requisition_lines_all rl
where ms.req_line_id = rl.requisition_line_id
and rl.requisition_line_id =RequisitionLineId;
SUPPLY_TYPE_CODE=SHIPMENT
SUPPLY_SOURCE_ID=66367
REQ_HEADER_ID=56678
REQ_LINE_ID=60678
SHIPMENT_HEADER_ID=59417
SHIPMENT_LINE_ID=66367
ITEM_ID=149
QUANTITY=10
UNIT_OF_MEASURE=Each
NEED_BY_DATE=05-APR-06
EXPECTED_DELIVERY_DATE=07-APR-06
DESTINATION_TYPE_CODE=INVENTORY
FROM_ORGANIZATION_ID=210
TO_ORGANIZATION_ID=209
6.6) You may also run the OMSE11i.SQL release 11i script. for the Sales Order Note 133464.1
In order to find the sales order number please do the following in Purchasing responsibility:
1. Open Requisition Summary
2. Enter Requisition and Line then Find
3. View Sales Orders
If only the internal requisition number is known and not the sales order number,
following query can be used to find the sales order number:

Select ORDER_NUMBER, ORIG_SYS_DOCUMENT_REF, SOURCE_DOCUMENT_ID
from OE_ORDER_HEADERS_ALL
where ORIG_SYS_DOCUMENT_REF like '&InternalReqNumber';

(SOURCE_DOCUMENT_ID = Requisition Header Id)
If only the shipment number is known following query can be used to retrieve internal requisition number from intransit shipment number:

Select prh.segment1 Internal_req_number,
prh.ORG_ID Operating_Unit,
prh.REQUISITION_HEADER_ID ,
rsh.SHIPMENT_NUM shipment_num,
rsl.SHIPMENT_LINE_ID shipment_line_id,
rsl.TO_ORGANIZATION_ID organization_id,
prl.REQUISITION_LINE_ID
FROM
rcv_shipment_headers rsh,
rcv_shipment_lines rsl,
po_requisition_headers_all prh,
po_requisition_lines_all prl
WHERE rsh.shipment_num like '&Shipment'
and rsh.receipt_source_code ='INTERNAL ORDER'
and rsh.shipment_header_id=rsl.shipment_header_id
and rsl.requisition_line_id = prl.requisition_line_id
and prl.requisition_header_id = prh.requisition_header_id
- RECEIVE/DELIVER to INVENTORY Transaction for Internal REQUISITION / Sales ORDER Example -
1) Insert via ROI a Direct DELIVER Receipt for Shipment Number '64883' (SHIPMENT_HEADER_ID=59417)
of 2 items in destination organization
Insert
. 1 record in RCV_HEADERS_INTERFACE table for the receipt header information
with SHIPMENT_NUM= '64883'
RECEIPT_SOURCE_CODE='INTERNAL ORDER'
and VALIDATION_FLAG='Y'
. 1 record in RCV_TRANSACTIONS_INTERFACE table for SHIPMENT_LINE_ID=66367
with TRANSACTION_TYPE='RECEIVE' and AUTO_TRANSACT_CODE='DELIVER'
for a quantity =2 indicating
DESTINATION_TYPE_CODE='INVENTORY'
RECEIPT_SOURCE_CODE='INTERNAL ORDER' and SOURCE_DOCUMENT_CODE='REQ'
VALIDATION_FLAG='Y'
and specifying
REQUISITION_LINE_ID= 60678
REQ_DISTRIBUTION_ID= 59631
SQL> INSERT INTO RCV_HEADERS_INTERFACE
(HEADER_INTERFACE_ID,
GROUP_ID,
PROCESSING_STATUS_CODE,
RECEIPT_SOURCE_CODE,
TRANSACTION_TYPE,
AUTO_TRANSACT_CODE,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_LOGIN,
CREATION_DATE,
CREATED_BY,
SHIPMENT_NUM,
SHIP_TO_ORGANIZATION_ID,
EXPECTED_RECEIPT_DATE,
SHIPPED_DATE,
EMPLOYEE_ID,
VALIDATION_FLAG
)
VALUES
(rcv_headers_interface_s.nextval , --HEADER_INTERFACE_ID
rcv_interface_groups_s.nextval, --GROUP_ID
'PENDING', --PROCESSING_STATUS_CODE
'INTERNAL ORDER', --RECEIPT_SOURCE_CODE
'NEW', --TRANSACTION_TYPE
'DELIVER', --AUTO_TRANSACT_CODE
SYSDATE, --LAST_UPDATE_DATE
0, --LAST_UPDATE_BY
0, --LAST_UPDATE_LOGIN
SYSDATE, --CREATION_DATE
0, --CREATED_BY
'64883', --SHIPMENT_NUM
209, --SHIP_TO_ORGANIZATION_ID
SYSDATE+1, --EXPECTED_RECEIPT_DATE
SYSDATE, --SHIPPED_DATE
13536, --EMPLOYEE_ID
'Y' --VALIDATION_FLAG
);
INSERT INTO RCV_TRANSACTIONS_INTERFACE
(INTERFACE_TRANSACTION_ID,
GROUP_ID,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
CREATION_DATE,
CREATED_BY,
LAST_UPDATE_LOGIN,
TRANSACTION_TYPE,
TRANSACTION_DATE,
PROCESSING_STATUS_CODE,
PROCESSING_MODE_CODE,
TRANSACTION_STATUS_CODE,
QUANTITY,
UNIT_OF_MEASURE,
INTERFACE_SOURCE_CODE,
ITEM_ID,
EMPLOYEE_ID,
AUTO_TRANSACT_CODE,
SHIPMENT_HEADER_ID,
SHIPMENT_LINE_ID,
SHIP_TO_LOCATION_ID,
RECEIPT_SOURCE_CODE,
TO_ORGANIZATION_ID,
SOURCE_DOCUMENT_CODE,
REQUISITION_LINE_ID,
REQ_DISTRIBUTION_ID,
DESTINATION_TYPE_CODE,
DELIVER_TO_PERSON_ID,
LOCATION_ID,
DELIVER_TO_LOCATION_ID,
SUBINVENTORY,
SHIPMENT_NUM,
EXPECTED_RECEIPT_DATE,
SHIPPED_DATE,
HEADER_INTERFACE_ID,
VALIDATION_FLAG
)
VALUES
( rcv_transactions_interface_s.nextval, -- INTERFACE_TRANSACTION_ID
rcv_interface_groups_s.currval, --GROUP_ID
SYSDATE, --LAST_UPDATE_DATE
0, --LAST_UPDATED_BY
SYSDATE, --CREATION_DATE
0, --CREATED_BY
0, --LAST_UPDATE_LOGIN
'RECEIVE', --TRANSACTION_TYPE
SYSDATE, --TRANSACTION_DATE
'PENDING', --PROCESSING_STATUS_CODE
'BATCH', --PROCESSING_MODE_CODE
'PENDING', --TRANSACTION_STATUS_CODE
2, --QUANTITY
'Each', --UNIT_OF_MEASURE
'RCV', --INTERFACE_SOURCE_CODE
149, --ITEM_ID
13536, --EMPLOYEE_ID
'DELIVER', --AUTO_TRANSACT_CODE
59417, --SHIPMENT_HEADER_ID
66367, --SHIPMENT_LINE_ID
209, --SHIP_TO_LOCATION_ID
'INTERNAL ORDER', --RECEIPT_SOURCE_CODE
209, --TO_ORGANIZATION_ID
'REQ', --SOURCE_DOCUMENT_CODE
60678, --REQUISITION_LINE_ID
59631, --REQ_DISTRIBUTION_ID
'INVENTORY', --DESTINATION_TYPE_CODE
13536, --DELIVER_TO_PERSON_ID
209, --LOCATION_ID
209, --DELIVER_TO_LOCATION_ID
'Stores', --SUBINVENTORY
'64883', --SHIPMENT_NUM
SYSDATE+1, --EXPECTED_RECEIPT_DATE,
SYSDATE, --SHIPPED_DATE
rcv_headers_interface_s.currval, --HEADER_INTERFACE_ID
'Y' --VALIDATION_FLAG
);
Commit;
Note: On R12 instance, RHI.org_id or RTI.org_id should also be populated.
2) Run the following scripts to check data have been correctly inserted
SQL> Select * from RCV_HEADERS_INTERFACE where SHIPMENT_NUM like 'Shipment_Num';
GROUP_ID=21309
HEADER_INTERFACE_ID=40152
RECEIPT_SOURCE_CODE=INTERNAL ORDER
SHIPMENT_NUM=64883
VALIDATION_FLAG=Y
SQL> Select * from RCV_TRANSACTIONS_INTERFACE where SHIPMENT_NUM like 'Shipment_Num';
INTERFACE_TRANSACTION_ID=67448
GROUP_ID=21309
HEADER_INTERFACE_ID=40152
TRANSACTION_TYPE=RECEIVE
AUTO_TRANSACT_CODE=DELIVER
RECEIPT_SOURCE_CODE=INTERNAL ORDER
TO_ORGANIZATION_ID=209
SOURCE_DOCUMENT_CODE=REQ
REQUISITION_LINE_ID=60678
REQ_DISTRIBUTION_ID=59631
SHIPMENT_NUM=64883
VALIDATION_FLAG=Y
3) In Purchasing Responsibility, Change to receiving organization M2 and
run the Receiving Transaction Processor for the given group_id used in RHI and RTI (GROUP_ID=21309)
4) Navigate to Receiving / Receiving Transactions Summary form
For Internal Requisition 5709, Receipt Number 5020 on Shipment Number 64883 has
Receive and Deliver transactions.
5) Check how the following application tables have been populated/updated
SQL> Select * from RCV_HEADERS_INTERFACE where SHIPMENT_NUM like 'Shipment_Num';
GROUP_ID=21309
HEADER_INTERFACE_ID=40152
PROCESSING_STATUS_CODE=SUCCESS
RECEIPT_SOURCE_CODE=INTERNAL ORDER
SHIPMENT_NUM=64883
SQL> Select * from RCV_TRANSACTIONS where REQUISITION_LINE_ID=60678
It returns 2 records
For TRANSACTION_TYPE=RECEIVE
TRANSACTION_ID=110699
DESTINATION_TYPE_CODE=RECEIVING
PARENT_TRANSACTION_ID=-1
QUANTITY=2
For TRANSACTION_TYPE=DELIVER
TRANSACTION_ID=110700
DESTINATION_TYPE_CODE=INVENTORY
PARENT_TRANSACTION_ID=110699
QUANTITY=2

Wednesday, July 3, 2013

NESTED TABLE INITIALIZATION - Work in Progress


CREATE OR REPLACE TYPE APPS.wwt_xx_wms_serial_number_type AS TABLE OF VARCHAR2 (30)


CREATE OR REPLACE TYPE APPS.wwt_xxwms_item_reserve_rectype AS OBJECT (
   doc_name             VARCHAR2 (100),
   doc_source_type_id   NUMBER,
   doc_header_id        NUMBER,
   doc_line_id          NUMBER,
   inventory_item_id    NUMBER,
   uom                  VARCHAR2 (10),
   quantity             NUMBER,
   serial_number        wwt_xx_wms_serial_number_type
)

CREATE OR REPLACE TYPE APPS.wwt_xxwms_item_reserve_tabtype AS TABLE OF apps.wwt_xxwms_item_reserve_rectype


DECLARE

   l_return_status         VARCHAR2 (10);
   l_return_message        VARCHAR2 (32000);
   l_item_reservation_rec  wwt_xxwms_item_reserve_rectype := wwt_xxwms_item_reserve_rectype (null,null,null,null,null,null,null,wwt_xx_wms_serial_number_type() );
   l_item_reservation_tbl  wwt_xxwms_item_reserve_tabtype := wwt_xxwms_item_reserve_tabtype();

BEGIN

    l_item_reservation_rec  := wwt_xxwms_item_reserve_rectype (null,null,null,null,null,null,null,wwt_xx_wms_serial_number_type() );
    l_item_reservation_rec.doc_line_id := 24550833;
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(1) := 'X531316060';
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(2) := 'X531316061';  

    l_item_reservation_tbl.EXTEND;
    l_item_reservation_tbl(1) := l_item_reservation_rec;  


    l_item_reservation_rec  := wwt_xxwms_item_reserve_rectype (null,null,null,null,null,null,null,wwt_xx_wms_serial_number_type() );
    l_item_reservation_rec.doc_line_id := 24550834;
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(1) := 'X531316062';
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(2) := 'X531316063';  
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(3) := 'X531316064';  
    l_item_reservation_rec.serial_number.EXTEND;
    l_item_reservation_rec.serial_number(4) := 'X531316065';  

    l_item_reservation_tbl.EXTEND;
    l_item_reservation_tbl(2) := l_item_reservation_rec;  



    FOR idx IN l_item_reservation_tbl.FIRST .. l_item_reservation_tbl.LAST LOOP
 
       DBMS_OUTPUT.put_line ( idx||'Doc line id '||l_item_reservation_tbl(idx).doc_line_id);  

       FOR srl_idx IN l_item_reservation_tbl(idx).serial_number.FIRST .. l_item_reservation_tbl(idx).serial_number.LAST   LOOP
     
       DBMS_OUTPUT.put_line (srl_idx|| 'serial number '||l_item_reservation_tbl(idx).serial_number(srl_idx));  
     
       END LOOP;
       
    END LOOP;


   DBMS_OUTPUT.put_line ('l_return_status => ' || l_return_status);
   DBMS_OUTPUT.put_line ('ln_msg_count => ' || l_return_message);


END;

Thursday, June 20, 2013

Serial number is not available when doing any inventory transaction but shows in on hand quantity interface


I was facing problem in one of my client site that oracle shows on hand quantity for one item in on hand quantity screen with serial numbers but when user is going to transact it either by sub inventory transfer or by Miscellaneous issue it shows me on hand� zero on transactional form

I have investigated it in detail and find different notes on Metalink for the solution and fusion of these notes is solution
First of all get Inventory Item id , serial number and organization id from on hand quantity interface by using examine option.

Step 1

Run the following query to check exact status of that serial numbers

SELECT SUBSTR (inventory_item_id, 1, 9) “Item Id”,
 SUBSTR (serial_number, 1, 20) “Serial Number”,
SUBSTR (current_organization_id, 1, 9) “Organization Id”,
SUBSTR (lot_number, 1, 18) “Lot Number”,
SUBSTR (DECODE (current_status,
1, ‘Defined but not used’,
3, ‘Resides in Stores’,
4, ‘Out of Stores’,
5, ‘Intransit’,
6, ‘Invalid’,
NULL, ‘Verify Serial Number’,
current_status
 ),
1,
25
) “Status”,
SUBSTR (current_subinventory_code, 1, 25) “Subinv”,
 SUBSTR (current_locator_id, 1, 9) “Locator”,
 SUBSTR (group_mark_id, 1, 15) “Group Mark Id”,
SUBSTR (line_mark_id, 1, 15) “Line Mark Id”,
 SUBSTR (lot_line_mark_id, 1, 15) “Lot Line Mark Id”, group_mark_id,
 line_mark_id, lot_line_mark_id
FROM mtl_serial_numbers
WHERE inventory_item_id = ‘&EnterItemID’
AND serial_number = ‘&EnterSerialNumber’
AND current_organization_id = ‘&EnterOrgID’

Above query shows me the status �Resides in Stores� but this serial number is not displayed in transactional forms

Step 2
Then run the following query

SELECT i.inventory_item_id itemname, s.inventory_item_id itemid,
s.serial_number serialno, s.current_organization_id org,
s.current_subinventory_code sub, s.current_status stat,
 s.group_mark_id gmid, s.line_mark_id lmid, s.lot_line_mark_id
 FROM mtl_system_items i, mtl_serial_numbers s
WHERE inventory_item_id = ‘&EnterItemID’
AND serial_number = ‘&EnterSerialNumber’
AND current_organization_id = ‘&EnterOrgID’
AND s.current_organization_id = i.organization_id
AND s.inventory_item_id = i.inventory_item_id;

Check the value of following columns

1.�group_mark_id
This column is Group identifier (used by Oracle Inventory for ensuring that serial numbers used by one user’s session do not become available incorrectly to another user)
2.�line_mark_id
This column Used by Oracle Inventory for ensuring that serial numbers used by one user’s session do not become available incorrectly to another user. The column is used by Oracle Inventory’s serial number marking and unmarking routines
3.�lot_line_mark_id
Identifier used in serial number marking and unmarking routines

Step 3

If value of above mentioned column is not blank / null then run following query
UPDATE mtl_serial_numbers
SET group_mark_id = NULL,
line_mark_id = NULL,
 lot_line_mark_id = NULL
WHERE inventory_item_id = ‘&EnterItemID’
AND serial_number = ‘&EnterSerialNumber’��
AND current_organization_id = ‘&EnterOrgID’
AND current_status = 3
A serial number can have one of following statuses
1.�Defined but not used
2.�Resides in stores
3.�Issued out of stores
4.�Resides in transit

I used status = 3 in above query as I was looking for only those serial numbers which Resides in stores but not available to me for transaction

Step 4
Commit the record and then check are you able for transaction or not