R13 Currency Precision Extension Solution-V3

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 15

An Oracle White Paper

January 2018

R13 Currency Precision Extensions


Disclaimer
The following is intended to outline our general product direction. It is intended for
information purposes only, and may not be incorporated into any contract. It is not a
commitment to deliver any material, code, or functionality, and should not be relied upon in
making purchasing decisions. The development, release, and timing of any features or
functionality described for Oracle’s products remains at the sole discretion of Oracle.
Functional Description of the Use Case :
Out of the box, Pricing rounds the Unit Price and Extended Amounts calculated on sales order
lines and other transaction lines priced to the standard currency precision of the Header currency.
Pricing does a post rounding. This means, the extended amount is calculated using the unrounded
unit price and then round the unit price as well as the extended amount. Pricing does this to make
sure that the extended amount accurately reflects the amount the customer would have to pay.
Eg. Lets say Unit Price = 9.049123 and Quantity = 10,
Extended Amount = 9.049123 * 10 = 90.49123
Round Unit Price = round(9.0491,2) = 9.05
Round Extended Amount = round(90.491,2) = 90.49
Here are the issues we have seen customers face because of this rounding:
Issue# Description
1 Invoice Amount on discount lines is not adding up
2 Unit Price is not displayed to the precision defined on the price list

Customers who wish encounter the above issues or feel that this does not meet their
requirements can leverage algorithm extensions to change this functionality.
Customers can make changes to the algorithm to round the header currency unit price to the
currency extended precision and round the header currency extended amount to the standard
currency precision.
With this, in the above example, the unit price will be 9.04912 and the extended amount for a
quantity of 10 will be 90.49.
Customizations Steps

1. Algorithm Primer
2. Algorithm Changes
3. Upgrade Considerations
4. Test the changes
5. FAQ & Known Issues

1. Algorithm Primer
Here is a reference to the algorithm primer. We recommend reading this is as a pre-
requisite before starting algorithm customizations.

2. Algorithm Changes

a. In Fusion Pricing -> Manage Algorithms, search for algorithm ‘Compute


Extended Amounts in Header Currency', click on the most current version used
in FOM Pricing, click Actions -> Create Version, say this creates Version 2. Click
Actions -> Edit, Edit the description to add to the existing one a brief note on
the functionality being achieved via the customization and the name of the
person who can be contacted in case of issues eg. 'This version does rounds the
HeaderCurrencyUnitPrice to Extended Precision. Author: Jdoe.'

b. Click on the Functions Tab


1. Click on the function ‘getCurrencyPrecision’
2. Click on the ‘View Object Query’ Tab
3
3. Check the Single Row check box as shown below

c. Click on the Step ‘Get Header Currency Precision’


1. Click on the Condition field
2. Modify the Condition to below, the changes shown in Red.
false && Param.OutputStatus == 'SUCCESS' && Header.MessageTypeCode != 'ERROR'
&& Header.CheckCurrencyPrecision && finer('-------- Compute HeaderCurrency
ExtendedAmount : GetHeaderCurrencyPrecision --------') == null

d. Click on the step ‘Flag Currency Conversion’


In the Default Action, replace the existing code (in italics below for reference)
with the code in bold. Actual changes in Red
//No Currency Conversion needed. Default ExtendedAmount as
HeaderCurrencyExtendedAmount
finest('No Header Currency Conversion -- CompId: ' +
ChargeComponent.ChargeComponentId)
ChargeComponent.HeaderCurrencyCode =
ChargeComponent.CurrencyCode
ChargeComponent.createDataObject('HeaderCurrencyUnitPrice')
ChargeComponent.HeaderCurrencyUnitPrice.Value =
ChargeComponent?.UnitPrice?.Value
ChargeComponent.HeaderCurrencyUnitPrice.CurrencyCode=
Header.AppliedCurrencyCode

4
// bug 22806194 round unitprice to precision
if ( Header.CurrencyPrecision != null ) {
ChargeComponent.HeaderCurrencyUnitPrice?.Value =
round(ChargeComponent.HeaderCurrencyUnitPrice?.Value,
Header.CurrencyPrecision)
}

if (Charge.PricedQuantity != null) {
finest('\tPriced quantity ' + Charge.PricedQuantity.Value + ' ' +
Charge.PricedQuantity.UnitCode)

ChargeComponent.createDataObject('HeaderCurrencyExtendedAmo
unt')
ChargeComponent.HeaderCurrencyExtendedAmount.Value =
ChargeComponent?.ExtendedAmount?.Value

ChargeComponent.HeaderCurrencyExtendedAmount.CurrencyCode=
Header.AppliedCurrencyCode

if (null != ChargeComponent?.CoverageExtendedAmount?.Value) {

ChargeComponent.createDataObject('HeaderCurrencyCoverageExte
ndedAmount')

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value
= ChargeComponent.CoverageExtendedAmount.Value

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Curre
ncyCode= Header.AppliedCurrencyCode
}

// bug 22806194 round Extended Amounts to precision


if ( Header.CurrencyPrecision != null ) {
ChargeComponent.HeaderCurrencyExtendedAmount?.Value =
round(ChargeComponent.HeaderCurrencyExtendedAmount?.Value,
Header.CurrencyPrecision)
if (null !=
ChargeComponent.HeaderCurrencyCoverageExtendedAmount?.Valu
e) {

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value
=

round(ChargeComponent.HeaderCurrencyCoverageExtendedAmount
.Value, Header.CurrencyPrecision)
}
}
}
-------------------------------------------------------------------------------------------
---

5
With
-------------------------------------------------------------------------------------------
---
//No Currency Conversion needed. Default ExtendedAmount as
HeaderCurrencyExtendedAmount
finest('No Header Currency Conversion -- CompId: ' +
ChargeComponent.ChargeComponentId)
ChargeComponent.HeaderCurrencyCode =
ChargeComponent.CurrencyCode
ChargeComponent.createDataObject('HeaderCurrencyUnitPrice')
ChargeComponent.HeaderCurrencyUnitPrice.Value =
ChargeComponent?.UnitPrice?.Value
ChargeComponent.HeaderCurrencyUnitPrice.CurrencyCode=
Header.AppliedCurrencyCode

//Get Currency Precision

def CurrencyDetail =
getCurrencyPrecision(ChargeComponent.HeaderCurrencyCode)

// new  Modifying this to round to Extended Precision for Unit


Price
if ( CurrencyDetail != null ) {
ChargeComponent.HeaderCurrencyUnitPrice?.Value =
round(ChargeComponent.HeaderCurrencyUnitPrice?.Value,
CurrencyDetail.ExtendedPrecision)

if (Charge.PricedQuantity != null) {
finest('\tPriced quantity ' + Charge.PricedQuantity.Value + ' ' +
Charge.PricedQuantity.UnitCode)

ChargeComponent.createDataObject('HeaderCurrencyExtendedAm
ount')
ChargeComponent.HeaderCurrencyExtendedAmount.Value =
ChargeComponent?.ExtendedAmount?.Value

ChargeComponent.HeaderCurrencyExtendedAmount.CurrencyCode
= Header.AppliedCurrencyCode

if (null != ChargeComponent?.CoverageExtendedAmount?.Value)
{

ChargeComponent.createDataObject('HeaderCurrencyCoverageExt
endedAmount')

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Valu
e = ChargeComponent.CoverageExtendedAmount.Value

6
ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Curr
encyCode= Header.AppliedCurrencyCode
}

// new  round Extended Amounts to Currency Standard Precision


if ( CurrencyDetail != null ) {
ChargeComponent.HeaderCurrencyExtendedAmount?.Value =
round(ChargeComponent.HeaderCurrencyExtendedAmount?.Value
, CurrencyDetail.Precision)
if (null !=
ChargeComponent.HeaderCurrencyCoverageExtendedAmount?.Val
ue) {

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Valu
e=

round(ChargeComponent.HeaderCurrencyCoverageExtendedAmou
nt.Value, CurrencyDetail.Precision)
}
}

e. Click on step ‘Compute Header Currency Extended Amount’


In the Default Action, replace the existing code (in italics below for reference)
with the code in bold. Actual changes in Red.
finer('-------- Compute Header Currency Extended Amount : ComponentId -
'+ChargeComponent.ChargeComponentId+' From to Currencies:
'+ChargeComponent.CurrencyCode+' to '+Header.AppliedCurrencyCode+'
--------')
if ( ConvRate?.MessageTypeCode == 'ERROR' ) {
finest('creating line message')
Line.MessageTypeCode = 'ERROR'
Charge.MessageTypeCode = 'ERROR'
msg =
Message.locate([ParentEntityCode:'LINE',ParentEntityId:Line.LineId,Message
Text:ConvRate.PrcErrorMessage])
if ( msg == null ) {
// create new error message for Line
msg = Message.insert([PricingMessageId:getNextId()])
msg.MessageText = ConvRate.PrcErrorMessage
msg.ParentEntityCode = 'LINE'
msg.ParentEntityId = Line.LineId
msg.MessageTypeCode = Line.MessageTypeCode
msg.MessageName = ConvRate.PrcMessageName
}
}
else {
finer('-------- Compute Header Currency Extended Amount : ComponentId -

7
'+ChargeComponent.ChargeComponentId+' UnitPrice:
'+ChargeComponent.UnitPrice?.Value+' ConvRate:
'+ConvRate?.ConversionRate+' -----')
ChargeComponent.HeaderCurrencyCode = Header.AppliedCurrencyCode

ChargeComponent.createDataObject('HeaderCurrencyUnitPrice')
ChargeComponent.HeaderCurrencyUnitPrice.Value =
ChargeComponent?.UnitPrice?.Value * (ConvRate.ConversionRate?:1)
finer('-------- Compute Header Currency Extended Amount : Computed
HeaderCurrencyUnitPrice -
'+ChargeComponent.HeaderCurrencyUnitPrice?.Value+' -----')
ChargeComponent.HeaderCurrencyUnitPrice.CurrencyCode =
ChargeComponent.HeaderCurrencyCode

ChargeComponent.createDataObject('HeaderCurrencyExtendedAmount')
ChargeComponent.HeaderCurrencyExtendedAmount.Value =
ChargeComponent?.ExtendedAmount?.Value *
(ConvRate.ConversionRate?:1)
ChargeComponent.HeaderCurrencyExtendedAmount.CurrencyCode =
ChargeComponent.HeaderCurrencyCode

if (null != ChargeComponent?.CoverageExtendedAmount?.Value) {

ChargeComponent.createDataObject('HeaderCurrencyCoverageExtendedAm
ount')
ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value =
ChargeComponent.CoverageExtendedAmount.Value *
(ConvRate.ConversionRate?:1)

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.CurrencyCode
= ChargeComponent.HeaderCurrencyCode
}

// round to precision
if ( Header.CurrencyPrecision != null ) {
ChargeComponent.HeaderCurrencyUnitPrice?.Value =
round(ChargeComponent.HeaderCurrencyUnitPrice?.Value,
Header.CurrencyPrecision)
ChargeComponent.HeaderCurrencyExtendedAmount?.Value =
round(ChargeComponent.HeaderCurrencyExtendedAmount?.Value,
Header.CurrencyPrecision)
if (null !=
ChargeComponent.HeaderCurrencyCoverageExtendedAmount?.Value) {
ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value
=

round(ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value,
Header.CurrencyPrecision)
}
}
}

8
------------------------------------------------------------------------------------------------------
-
with
------------------------------------------------------------------------------------------------------
-
finer('-------- Compute Header Currency Extended Amount : ComponentId -
'+ChargeComponent.ChargeComponentId+' From to Currencies:
'+ChargeComponent.CurrencyCode+' to '+Header.AppliedCurrencyCode+'
--------')
if ( ConvRate?.MessageTypeCode == 'ERROR' ) {
finest('creating line message')
Line.MessageTypeCode = 'ERROR'
Charge.MessageTypeCode = 'ERROR'
msg =
Message.locate([ParentEntityCode:'LINE',ParentEntityId:Line.LineId,Messag
eText:ConvRate.PrcErrorMessage])
if ( msg == null ) {
// create new error message for Line
msg = Message.insert([PricingMessageId:getNextId()])
msg.MessageText = ConvRate.PrcErrorMessage
msg.ParentEntityCode = 'LINE'
msg.ParentEntityId = Line.LineId
msg.MessageTypeCode = Line.MessageTypeCode
msg.MessageName = ConvRate.PrcMessageName
}
}
else {
finer('-------- Compute Header Currency Extended Amount : ComponentId
- '+ChargeComponent.ChargeComponentId+' UnitPrice:
'+ChargeComponent.UnitPrice?.Value+' ConvRate:
'+ConvRate?.ConversionRate+' -----')
ChargeComponent.HeaderCurrencyCode = Header.AppliedCurrencyCode

ChargeComponent.createDataObject('HeaderCurrencyUnitPrice')
ChargeComponent.HeaderCurrencyUnitPrice.Value =
ChargeComponent?.UnitPrice?.Value * (ConvRate.ConversionRate?:1)
finer('-------- Compute Header Currency Extended Amount : Computed
HeaderCurrencyUnitPrice -
'+ChargeComponent.HeaderCurrencyUnitPrice?.Value+' -----')
ChargeComponent.HeaderCurrencyUnitPrice.CurrencyCode =
ChargeComponent.HeaderCurrencyCode

ChargeComponent.createDataObject('HeaderCurrencyExtendedAmount')
ChargeComponent.HeaderCurrencyExtendedAmount.Value =
ChargeComponent?.ExtendedAmount?.Value *
(ConvRate.ConversionRate?:1)
ChargeComponent.HeaderCurrencyExtendedAmount.CurrencyCode =
ChargeComponent.HeaderCurrencyCode

if (null != ChargeComponent?.CoverageExtendedAmount?.Value) {

9
ChargeComponent.createDataObject('HeaderCurrencyCoverageExtendedA
mount')
ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value =
ChargeComponent.CoverageExtendedAmount.Value *
(ConvRate.ConversionRate?:1)

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.CurrencyCo
de = ChargeComponent.HeaderCurrencyCode
}

// New Round Unit Price to Currency Extended Precision and Extended


Amount to Standard precision

def CurrencyDetail =
getCurrencyPrecision(ChargeComponent.HeaderCurrencyCode)

if ( CurrencyDetail != null ) {
ChargeComponent.HeaderCurrencyUnitPrice?.Value =
round(ChargeComponent.HeaderCurrencyUnitPrice?.Value,
CurrencyDetail.ExtendedPrecision)
ChargeComponent.HeaderCurrencyExtendedAmount?.Value =
round(ChargeComponent.HeaderCurrencyExtendedAmount?.Value,
CurrencyDetail.Precision)
if (null !=
ChargeComponent.HeaderCurrencyCoverageExtendedAmount?.Value) {

ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value =

round(ChargeComponent.HeaderCurrencyCoverageExtendedAmount.Value
, CurrencyDetail.Precision)
}
}
}

f. After making all the changes, Save the algorithm, re-open ‘Manage Algorithms’
page, select the latest version of the Algorithm ‘Compute Extended Amounts in
Header Currency', Click Actions -> Publish.
g. Sign-out and Sign back into OM and reprice the order, you should see the
changes in the extended amounts now.
Note:
The Unit Price may still be display the precision based on the User
preferences. The user preferences only supports displaying upto 3-digit
precision. But the prices stored in OM on the Charge Components will store
the Unit Price in the currency extended precision and extended amount in
standard precision

Note:
1. If your order has the same currency as the price list
And if there is an active Rounding Rule defined in Pricing Setup and Maintenance task
‘Manage Rounding Rules’ and ‘Manage Rounding Rule Assignments’, the list and net

1
price in
the charge currency are rounded based on the Rounding Rule.
The Header Currency Unit price and Extended Amounts are rounded based on the
Extended and Standard precision of the Order Currency
2. While testing the above extension solution, be sure to test the currency
conversion case when the order currency us different than the price list
currency

3. Upgrade Considerations

a. Whenever you upgrade to a newer version, please ensure that these changes are
reconciled with the newest version of the algorithm “Compute Extended Amounts
in Header Currency “. When you have questions are unable to decide what
changes are needed, please log an SR with support and upload this document as a
reference.

4. Test the changes

a. Test the Price Sales Transaction thoroughly to make sure this works correctly.

b. Here is a test payload to test the Price Sales Transactions Algorithm. Make the necessary
changes noted in the payload. In the Test tab, create a test case with Test Case Name =
"Precision Test". Under the Test Input tab, select the row with Variable Name 'Price
Request', edit the default Variable Value, select all the lines of the default payload and
paste the payload below. Click the 'Run' button. Now click the Test Output tab and you will
see that the discount with the specified PricingTermId is applied on the line.

Test Input Payload


<?xml version="1.0" encoding="UTF-8"?>
<PriceRequestInternal:PriceRequestInternalType
xmlns:ns0="http://xmlns.oracle.com/adf/svc/types/"
xmlns:PriceRequestInternal="http://xmlns.oracle.com/apps/scm/pricing/
priceExecution/pricingProcesses/pricingInternal/PricingInternal"
Change the attribute values for CustomerId xxx,
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SellingBusinessUnit xx1 and SellingLegalEntityId xx2 to a valid
xsi:type="PriceRequestInternal:PriceRequestInternalType"><PriceRequestInternal:Hea
customerId in your system
der>
Check the FAQ on how to retrieve the IDs for the values
<PriceRequestInternal:CustomerId>xxx</PriceRequestInternal:CustomerId>
shaded in RED in the payload
<PriceRequestInternal:HeaderId>101</PriceRequestInternal:HeaderId>

<PriceRequestInternal:CalculatePricingChargesFlag>true</PriceRequestInternal:Calcu
latePricingChargesFlag>
<PriceRequestInternal:CalculateShippingChargesFlag>false</PriceRequestInternal:Cal
culateShippingChargesFlag>
<PriceRequestInternal:CalculateTaxFlag>false</
PriceRequestInternal:CalculateTaxFlag>
<PriceRequestInternal:SellingBusinessUnitId>xx1</PriceRequestInternal:SellingBusin
1
essUnitId>

<PriceRequestInternal:SellingLegalEntityId>xx2</PriceRequestInternal:SellingLegalE
ntityId>

<PriceRequestInternal:TransactionTypeCode>ORA_SALES_ORDER</PriceRequestInternal:Tr
ansactionTypeCode>
</PriceRequestInternal:Header>
<PriceRequestInternal:PricingServiceParameter>

<PriceRequestInternal:PricingContext>SALES</PriceRequestInternal:PricingContext>
</PriceRequestInternal:PricingServiceParameter>
<PriceRequestInternal:Line>
<PriceRequestInternal:HeaderId>101</PriceRequestInternal:HeaderId>

<PriceRequestInternal:InventoryItemId>yyy</PriceRequestInternal:InventoryItemId>

<PriceRequestInternal:InventoryOrganizationId>yy1</PriceRequestInternal:InventoryO
rganizationId>
<PriceRequestInternal:LineId>1001</PriceRequestInternal:LineId>

<PriceRequestInternal:LineCategoryCode>ORDER</PriceRequestInternal:LineCategoryCod
e>
<PriceRequestInternal:LineQuantity unitCode="yy2"
xmlns:tns="http://xmlns.oracle.com/adf/svc/errors/">2</PriceRequestInternal:LineQu
antity>

<PriceRequestInternal:LineQuantityUOMCode>yy2</PriceRequestInternal:LineQuantityUO
MCode>

<PriceRequestInternal:LineTypeCode>ORA_BUY</PriceRequestInternal:LineTypeCode>
</PriceRequestInternal:Line>

<PriceRequestInternal:ChangeSummary logging="false" xmlns:sdo="commonj.sdo"/>


</PriceRequestInternal:PriceRequestInternalType>

5. FAQ & Known Issues

1 SQLs to derive the IDs in the Test Input Payload


Header Attributes
Header.CustomerId
Header.SellingBusinessUnitId
Header.SellingLegalEntityId
Create an order with the Customer and BU that you want to use for testing and note the Order# eg.
12345. Then use the query below replacing the $OrderNumber with the OrderNumber of the Order
you created.
select header_id, sold_to_party_id as CustomerId, org_id as SellingBusinessUnitId, legal_entity_id as
SellingLegalEntityId
from doo_headers_all where Order_Number = $OrderNumber;

Line Attributes
Line.InventoryItemId
Line.InventoryOrganizationId
Line.LineQuantity.UOMCode
Line.LineQuantityUOMCode
Create an order line on the above order with the item that you want to use for testing. Then use the
query below to derive the IDs for the attributes above. Remember to replace the header_id in the
query below with the header_id returned in the query above. Note that the UOMCode "Ea" appears
in 2 places as highlighted in RED in the payload and both need to be replaced with the value returned
1
from the query.
select inventory_item_id as InventoryItemId, inventory_organization_id as InventoryOrganizationId,
ordered_uom as LineQuantityUOMCode from doo_fulfill_lines_all where header_id = $header_id;

Header EFF Attributes


PricingTerm_Custom

This needs to be replaced with Pricing_term_id retrieved from the query below based on the discount
rule that needs to be applied.
select name,pricing_term_id from qp_pricing_terms_vl where
parent_entity_type_code='DISCOUNT_LINE' and
PARENT_ENTITY_KEY_COLUMN1 in (select qp_discount_list_items.DISCOUNT_LIST_ITEM_ID from
qp_discount_list_items where
qp_discount_list_items.ITEM_LEVEL_CODE='ALL_ITEMS');

3 Error while publishing the algorithm:

Indication: This error occurs when there is a change made to the algorithm and when trying to publish
immediately after saving the changes.
Workaround: In the Manage Algorithms page, use the QBE as shown in the screen shot below, change
the search criteria eg. %Cust% and hit enter and perform the search and search again and then try
publishing. Once this error appears Actions->Deactivate, Actions->Activate and Actions -> Publish to
republish the algorithm.

4 Error(s) while testing algorithms in the Algorithm Tester

1
Indication: Error occurs when there are unsaved changes in the input payload and the user tries to
run the test case
Workaround: Save the changes before running the test case. Once the error appears, user needs to
Cancel the algorithm edit, go to the Manage Algorithm page, reopen the algorithm and re-run the test

1
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. This document is provided for information purposes only and the
January 2018
contents hereof are subject to change without notice. This document is not warranted to be error-free, nor subject to any other
Author: Priya Gopal
warranties or conditions, whether expressed orally or implied in law, including implied warranties and conditions of merchantability or
fitness for a particular purpose. We specifically disclaim any liability with respect to this document and no contractual obligations are
Oracle Corporation formed either directly or indirectly by this document. This document may not be reproduced or transmitted in any form or by any
World Headquarters means, electronic or mechanical, for any purpose, without our prior written permission.
500 Oracle Parkway
Redwood Shores, CA 94065 Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
U.S.A.
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and
Worldwide Inquiries:
are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are
Phone: +1.650.506.7000
trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open Group. 0612
Fax: +1.650.506.7200

oracle.com

You might also like