Back in 2009, I needed WIP completion transaction also be part of the Asset Creation process for depreciable items in Asset Tracking. The base was either R12.0.4 or R12.0.6, i don’t remember. But traditionally, for depreciable items,  following transactions are supported to create an asset in FA while the asset is still in Inventory.

  1. Miscellaneous Receipt
  2. Account Alias Receipt
  3. Account Receipt
  4. PO Receipt into Inventory
  5. PO Receipt into Projects
  6. Physical Inventory (Receipts)
  7. Cycle Counting (Receipts)

But there are companies that manuafacture products and they want to track them in FA. They typically get into inventory with WIP completion transaction. As you can see this transaction is not in the list above.
Recently, to my surprise, I found this patch 7489949 (which was released in 2008) that includes WIP completion also into supported transactions for asset creation. To add to my surprise, support had no clue when they were asked for solution at that time. Of course we came a long way.
BTW, it is included in base release of R12.1.1.

One of many cool features in SLA is creating manual journal entries. Many times we have a need to pass manual entries to reverse the entries happened a source transaction because the account is wrong or date is wrong or even the value is wrong. All sub ledgers give you a way to reverse the transaction and hence reverse the associated accounting entry. But sometimes you may run out of time and luck and resort to manual entries in GL. Once we are GL to enter manual entries for transactions that pertain to sub ledger, we lose an opportunity to reconcile as we do not have primary references for which we have created this accounting entry for. If we have any reports that are based on SLA tables the reconciliation becomes harder as we cannot link anything that happened in the GL with the SLA. After all, the purpose of SLA is to eliminate this risk of reconciliation with GL.
Also, I guess, Oracle Support uses this route (manual journal entries) to fix any entries that were corrupted in the original transaction.
While entering these manual entries we can capture original transaction attributes using supporting references feature where you can capture attributes like asset_id if it is Assets related entry, transaction_id if it is related to Inventory, invoice_Id for AP and customer_trx_id or cash_receipt_id if it is AR invoice or cash respectively, These give meaning to the manual journal entries.
Process comes in three steps: 
Creating entries, saving them as incomplete entries with in SLA to be posted later and finally completing this so that this will automatically transfer to GL, journal Import and Post them as needed. To create manual entries you need to assign a sub-function SLA: Create Subledger Journal Entry to the menu. It will appear as a button in the view journal entries page.
The same can be achieved with an API XLA_JOURNAL_ENTRIES_PUB_PKG. Also this is immensely useful if you want to create accounting entries related to transactions in legacy or related systems. You can capture the supporting references related to the related system for reconciliation purpose.
The best part of using this API is that, we do not have to separately code for Journal Import and Posting (with complete journals parameter to complete, transfer and post). The value you pass to this parameter takes care of that.
Sources:Oracle Financial Accounting Hub Implementation Guide (Chapter 12 on Manual Sub ledger Journal Entries API) and Oracle Subledger Accounting Implementation Guide (Chapter 6 Sub ledger Journal Entries).
As discussed in the earlier article Asset Tracking is all about two kinds of items: Depreciable and Normal Items. I already discussed normal items with simple inventory transactions earlier. Let us discuss depreciable items in this article. This is very peculiar situation where you will be receiving items into inventory and at the same time depreciating them by creating assets while it is sitting in your inventory.
Sounds odd but this is reality in a number of asset intensive industries. Take construction industry for example. All the equipment and material that is required to construct a plant or a building is typically stored on site. Here we should be able to keep track of inventory from planning perspective and at the same time some of the items while sitting in inventory on site. Asset tracking for depreciable items comes handy here.
The flow is very simple. You receive items against a purchase order and run one program which creates an asset for you in Fixed Assets. From then on the asset starts getting depreciated. But where it gets tricky is in accounting. Since we are receiving this into inventory as well as creating an asset in fixed asset, potentially we are counting the asset value twice. An asset value can be in inventory or assets not both. So how Oracle handles this? Also what happens if we dispose of or sell this asset? Let us examine the accounting entries for each transaction to understand this.
Take a case. Donald Drumps Construction Company is constructing a huge building in the suburbs of New York. A forklift was required to be purchased for the construction needs. This forklift is treated as an asset hence required to be created as asset. Hence a purchase order was raised and sent to the supplier to be delivered at the construction site. It costs $150,000 and the company uses standard costing.
Each construction site can be assigned a different organization or a Subinventory within an organization. A location should be created for this construction site in New York and assigned to this Subinventory. Important attributes in the item master to be enabled are shown here.
When the supplier sends forklift against this PO, someone on site receives into inventory. As soon it is received into inventory, IB gets created, marking the transaction (csi_transactions) ready to be processed for asset creation.
Accounting for PO Receipt transaction into Inventory is as shown here.
 Now as per the flow running the program Create Assets: Interface Inventory Transactions to Assets will interface the asset to the fixed assets taking this information from IB and inventory. Creation of assets also involves in an accounting entry as the asset value is increasing. So the accounting in this transaction is:
As you can see here, inventory account is used to credit, debiting the asset account taken from the asset category assigned to the item in the item master. So the inventory value goes down in balance sheet increasing the asset value from fixed asset. All this is happening at cost of the item. And the asset starts depreciating for the period of the project.
What happens after the building construction is done?
Out of a number of possibilities, two things can happen. This forklift can be moved to another site where construction is going on or simply after the project is successfully completed, this can be sold right from the site to another smaller construction company. If it is moved to another site (considered as Asset Move in Asset Tracking) depending on how the other site is configured in the system (different organization mapped to different asset book or same asset book), treatment in assets is different. But let us take the case where Mr. Drump is tired of this asset and would like to sell it off. Since quantity exists in inventory we can create a sales order and ship it. When you ship accounting is (assuming that he is selling at 60% of the cost as the equipment is already used):
 This is not good. As you can see we credited Inventory account twice. Once when we are creating asset and once shipping this forklift after usage. Also since we have shipped the asset to someone else, Mr. Drump should retire this asset from asset books by retiring the asset.
Asset Tracking handles this well. Inventory sends this shipping transaction message to IB which identifies the transaction to be eligible for asset retirement. Another program, called Interface Move Transactions to Assets is run to send the retirement message to Fixed Assets from IB. Asset retirement ensues.
But what about crediting the inventory account twice? To solve this issue there is another program we need to run to reverse the shipping accounting: Create Reversal GL entries For Inventory FA Items. This program identifies transactions that are eligible (rows in csi_transactions table with gl_interface_status_code flag set to 1) and inserts rows into gl_interface for importing into GL. So when you run this program, accounting is:
You can see that COGS account is not touched as revenue is involved and only Deferred COGS is touched. This might surprise you because, you thought, with the advent of Subledger Accounting, all transactions from sub-ledgers to GL flow through the Subledger Accounting application. Here is one accounting entry flowing into GL without Subledger accounting, making reconciliation harder for inventory.
Moreover this left credit balance in my deferred COGS account as you figured it out!
Points to consider:

  • Don’t be surprised to see inventory account having the source of Assets when reconciling inventory to GL. Also accounting flows from Asset Tracking but with the source of Inventory (reversals).
  • What happens to all those reports that are used to match the inventory value by quantity and inventory value in inventory account? The will not match here because quantity very well exists but the value in the account got credited elsewhere in assets and not in the inventory in of form of an issue.
What is Asset Tracking?
Asset Tracking in R12 (formerly known as Enterprise Installed Base), provides the functionality of operational and financial tracking of assets that are deployed in the feild as well as that are in inventory.
Assets in Procure to Pay
Traditionally we  have been creating assets in Fixed Assets using the Procure to Pay business flow. These POs have destination type as expense and not as inventory. Once the PO is matched to Invoice, Mass Additions Create Program sends assets to Mass Additions interface.
On the other hand Asset Tracking can create assets that are purchased into Inventory. While still being in Inventory, assets are created in fixed assets and depreciated. Operationally these assets are tracked in this application using the Installed Base’s current location. It uses Installed Base functionality as backbone to track the location of the assets.
Features of Asset Tracking
Asset Tracking is all about two kinds of items : Depreciable Items and Non-depreciable items. Depreciable items are those that depreciate while still being in Inventory. Non-Depreciable items are those that are still tracked as assets and depreciated while being “deployed” in the field (issued to field location or a project).
Foremost requirement for tracking an asset in this application is that the item is Intalled Base trackable. This is an attribute maintained in the item master. Using the integration between Inventory and Installed Base, all depreciable items, are created as assets as soon they are received into inventory.
All transactions coming from inventory and deployment transactions of Asset Tracking are tracked in Installed Base against the instance of this asset. Also Instance is linked to the financial asset in the installed base.
This application tracks the asset life cycle. When a depreciable item is received into inventory, asset gets created, but when it is sold or issued out the asset gets retired. On the otherside non-depreciable items are created as assets only when they are deployed not when they are in Inventory.
Alternatively assets can be created in the Fixed Assets first and then created in Asset Tracking, which automatically ties the asset and instance in Installed Base.
Integration of Asset Tracking
Integration of Asset TrackingAsset Tracking inherits all the integration that is out there for the Installed Base with other products. Asset Tracking integrates the operational aspects of the installed base with financial aspects of assets.
Here is the code snippet for creating items using API (traditionally we are used to use item open interface) in the Product Life Cycle Management process. While this does not replace loading items using open interface, this API can be used to manage the lifecycle of the item on a dialy basis.

Over a period time, companies conceptualize products, design them, build them, manage them and finally, retire them.

Here in the article I am introducing the API first. In the subsequent articles, we will manage the “lifecycle” of the product using the same API.

These code snippets are tested in 12.0.4.

CREATE OR REPLACE PACKAGE xx_create_item
IS
   g_miss_num    CONSTANT NUMBER       := 9.99e125;
   g_miss_char   CONSTANT VARCHAR2 (1) := CHR (0);
   g_miss_date   CONSTANT DATE         := TO_DATE (‘1’, ‘j’);
   g_false       CONSTANT VARCHAR2 (1) := fnd_api.g_false;                                                               
   g_true        CONSTANT VARCHAR2 (1) := fnd_api.g_true;

   PROCEDURE create_item (
      p_item_number         IN       VARCHAR2
    , p_description         IN       VARCHAR2
    , p_organization_id     IN       NUMBER
    , p_item_type           IN       VARCHAR2
    , x_inventory_item_id   OUT      NUMBER
    , x_organization_id     OUT      NUMBER
    , x_return_status       OUT      VARCHAR2
    , x_msg_count           OUT      NUMBER
    , x_msg_data            OUT      VARCHAR2
   );

   PROCEDURE create_item1 (
      p_item_number         IN       VARCHAR2
    , p_description         IN       VARCHAR2
    , p_organization_id     IN       NUMBER
    , p_item_type           IN       VARCHAR2
    , x_inventory_item_id   OUT      NUMBER
    , x_organization_id     OUT      NUMBER
    , x_return_status       OUT      VARCHAR2
    , x_msg_count           OUT      NUMBER
    , x_msg_data            OUT      VARCHAR2
   );
END xx_create_item;
/

CREATE OR REPLACE PACKAGE BODY xx_create_item
IS
   PROCEDURE create_item (
      p_item_number         IN       VARCHAR2
    , p_description         IN       VARCHAR2
    , p_organization_id     IN       NUMBER
    , p_item_type           IN       VARCHAR2
    , x_inventory_item_id   OUT      NUMBER
    , x_organization_id     OUT      NUMBER
    , x_return_status       OUT      VARCHAR2
    , x_msg_count           OUT      NUMBER
    , x_msg_data            OUT      VARCHAR2
   )
   IS
      l_template_id       NUMBER;
      x_item_id           NUMBER;
      x_org_id            NUMBER;
      l_item_number       VARCHAR2 (100);
      l_description       VARCHAR2 (4000);
      l_organization_id   NUMBER;
      v_msg_index_out     NUMBER;
      v_message           VARCHAR2 (100);
   BEGIN
      SELECT template_id
        INTO l_template_id
        FROM mtl_item_templates_b
       WHERE template_name = p_item_type;                                                                    

      l_item_number := p_item_number;
      l_description := p_description;
      l_organization_id := l_organization_id;
      ego_item_pub.process_item (p_api_version                 => 1.0
                               , p_transaction_type            => ‘CREATE’
                               , p_language_code               => ‘US’
                               , p_template_id               => 207
                               , p_organization_id             => 204
                               , p_master_organization_id      => 204
                               , p_description                 => ‘TEST113’
                               , p_long_description            => ‘TEST113’
                               , p_item_number                 => ‘TEST113’
                               , p_segment1                    => ‘TEST113’
                               , x_inventory_item_id           => x_inventory_item_id
                               , x_organization_id             => x_organization_id
                               , x_return_status               => x_return_status
                               , x_msg_count                   => x_msg_count
                               , x_msg_data                    => x_msg_data
                                );

      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;

   PROCEDURE create_item1 (
      p_item_number         IN       VARCHAR2
    , p_description         IN       VARCHAR2
    , p_organization_id     IN       NUMBER
    , p_item_type           IN       VARCHAR2
    , x_inventory_item_id   OUT      NUMBER
    , x_organization_id     OUT      NUMBER
    , x_return_status       OUT      VARCHAR2
    , x_msg_count           OUT      NUMBER
    , x_msg_data            OUT      VARCHAR2
   )
   IS
      l_template_id       NUMBER;
      l_item_number       VARCHAR2 (100);
      l_description       VARCHAR2 (4000);
      l_organization_id   NUMBER;
      v_msg_index_out     NUMBER;
      v_message           VARCHAR2 (100);
   BEGIN
      l_item_number := p_item_number;
      l_description := p_description;
      l_organization_id := p_organization_id;
      ego_item_pub.process_item (p_api_version            => 1.0
                               , p_transaction_type       => ‘CREATE’
                               , p_language_code          => ‘US’
                               , p_template_name          => p_item_type
                               , p_item_number            => l_item_number
                               , p_segment1               => l_item_number
                               , p_organization_id        => l_organization_id
                               , p_description            => l_item_number
                               , p_long_description       => l_item_number
                               , x_inventory_item_id      => x_inventory_item_id
                               , x_organization_id        => x_organization_id
                               , x_return_status          => x_return_status
                               , x_msg_count              => x_msg_count
                                );
   END;
END xx_create_item;
/

SHOW errors
/
DECLARE
   v_msg_index_out   NUMBER;
   x_item_id         NUMBER;
   x_org_id          NUMBER;
   x_return_status   VARCHAR2 (1);
   x_msg_count       NUMBER;
   x_msg_data        VARCHAR2 (4000);
   v_message         VARCHAR2 (4000);
BEGIN
   fnd_global.apps_initialize (1318, 50583, 401);
   inv_globals.set_org_id (204);
   xx_create_item.create_item1 (p_item_number            => ‘TEST111’
                             , p_description            => ‘TEST111’
                             , p_organization_id        => 204
                             , p_item_type              => ‘Finished Good’
                             , x_inventory_item_id      => x_item_id
                             , x_organization_id        => x_org_id
                             , x_return_status          => x_return_status
                             , x_msg_count              => x_msg_count
                             , x_msg_data               => x_msg_data
                              );
         DBMS_OUTPUT.put_line (‘Return Status is :’||x_return_status);                            
         DBMS_OUTPUT.put_line (‘Message Count is :’||x_msg_count);
         DBMS_OUTPUT.put_line (‘Create Item ID  is :’||x_item_id);
         DBMS_OUTPUT.put_line (‘Created in Organization is :’||x_org_id);

   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;
/

DECLARE
   v_msg_index_out   NUMBER;
   x_item_id         NUMBER;
   x_org_id          NUMBER;
   x_return_status   VARCHAR2 (1);
   x_msg_count       NUMBER;
   x_msg_data        VARCHAR2 (4000);
   v_message         VARCHAR2 (4000);
BEGIN
   –fnd_global.apps_initialize (1318, 50583, 401);
   inv_globals.set_org_id (204);
   xx_create_item.create_item1 (p_item_number            => ‘TEST111’
                             , p_description            => ‘TEST111’
                             , p_organization_id        => 204
                             , p_item_type              => ‘Finished Good’
                             , x_inventory_item_id      => x_item_id
                             , x_organization_id        => x_org_id
                             , x_return_status          => x_return_status
                             , x_msg_count              => x_msg_count
                             , x_msg_data               => x_msg_data
                              );
         DBMS_OUTPUT.put_line (‘Return Status is :’||x_return_status);                            
         DBMS_OUTPUT.put_line (‘Message Count is :’||x_msg_count);
         DBMS_OUTPUT.put_line (‘Create Item ID  is :’||x_item_id);
         DBMS_OUTPUT.put_line (‘Created in Organization is :’||x_org_id);

   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;