Tuesday, December 16, 2014

Switch single segment in account combination (CCID)

Occasionally I have a problem where the Debit and Credit entries in a subledger can’t balance due to mismatched balancing segment. The easy fix would be to change the segment the Code Combination ID (CCID), not the segments themselves, is stored in all the subledger accounting tables. One can’t just simply update the segment in a table but needs to find the proper CCID.

But what if the CCID does not exist, despite the account combination being valid? Simply inserting it into GL_CODE_COMBINATIONS could violate the cross-validation rules.

To address this problem, I wrote the simple function below that takes the original CCID as an input, switches the segment number provided in the p_segment_number parameter to value in the p_switch_to_parameter. 

Since it is all done using standard APIs it either :
  •          returns the existing  valid CCID of the new combination
  •           generates valid CCID if the combination does not exist
  •          returns 0 when the combination is invalid and  no CCID exists or can be generated


This function can be used for data fixes but also for custom accounting programs and table triggers, where one needs to change one or more segments in an account. In example if you want to have the same combination in the Receivables account as in COGS with only the natural account different the AR Autoaccounting rules do not have functionality to accomplish it. You could explore putting a trigger on RA_INTERFACE_LINES_ALL to insert a value into RA_INTERFACE_DISTRIBUTIONS_ALL as long as the function returns non zero CCID

Here is how I designed the function:

1. Translate the CCID into the segment combination

2. Find the number of segments in the combination

3. Replace the segment

5. Translate the new segment combination into a CCID. 


The last part was a bit  tricky because the CCID for the new combination may or may not exist and I didn't want to get into building a logic that would check it. In addition to that there was always risk that an invalid combination can be created, so it had to be validated against GL cross validation rules. Under other circumstances I might have used account generator workflow but I wanted to keep it as simple as possible and to be used in SQL so Workflow was out of  question


Let's translate the above points into APIs used:

1. FND_FLEX_EXT.get_segs('SQLGL', 'GL#',v_coa_id,p_CCID) -- concatenated account

2. FND_FLEX_EXT.breakup_segments(concatenated_segs => v_input_combination
,delimiter => p_delimiter
,segments => v_input_array);

3. v_output_array:=v_input_array;
v_output_array(p_segment_number):=p_switch_to;  -- replace the segment

4. FND_FLEX_EXT.get_ccid('SQLGL','GL#', v_coa_id, fnd_date.date_to_canonical(sysdate), v_output_combination); --recreate the new array as CCID.

Here is an example of how the function can be called:

select ccid,
fnd_flex_ext.get_segs('SQLGL', 'GL#',CHART_OF_ACCOUNTS_ID,ccID) old_code_combination,
new_ccid,
fnd_flex_ext.get_segs('SQLGL', 'GL#',CHART_OF_ACCOUNTS_ID,new_ccID) new_code_combination
from
(
SELECT CHART_OF_ACCOUNTS_ID,a.code_combination_id ccID,
xx_ccID.switch_CCID_segment (CODE_COMBINATION_ID,   --p_CCID
CHART_OF_ACCOUNTS_ID,  --p_coa_id
1,                     --p_segment_number
'02',                  --p_switch_to
'.'                    --p_delimiter
                              )
          new_ccid
  FROM gl_code_combinations a
 WHERE code_combination_id = 21704)







and the actual package code:


CREATE OR REPLACE PACKAGE APPS.XX_CCID
AS
Function switch_CCID_segment (p_CCID IN NUMBER,
p_coa_id IN number,
p_segment_number IN number,
p_switch_to IN varchar2,
p_delimiter IN varchar2)
 return number;


END XX_CCID ;
/

CREATE OR REPLACE package body APPS.XX_CCID
 as

  Function switch_CCID_segment (p_CCID IN NUMBER,
p_coa_id IN number,
p_segment_number IN number,
p_switch_to IN varchar2,
p_delimiter IN varchar2)
 return number IS



v_new_account number;

v_coa_id number;

v_input_combination varchar2(200);
v_output_combination varchar2(200);



v_input_array FND_FLEX_EXT.SegmentArray;

v_output_array FND_FLEX_EXT.SegmentArray;

v_number_of_segments number;



V_ERROR VARCHAR2(2000);

Begin


-- chart of accounts
v_coa_id:=p_coa_id;


-- get the combination from the ccid

v_input_combination := fnd_flex_ext.get_segs('SQLGL', 'GL#',v_coa_id,p_CCID) ;



-- this returns the number of segments but also feeds the segments to the v_input_array

v_number_of_segments:=FND_FLEX_EXT.breakup_segments(concatenated_segs => v_input_combination

,delimiter => p_delimiter

,segments => v_input_array);


v_output_array:=v_input_array;


--switch the segmentvalue
v_output_array(p_segment_number):=p_switch_to;

-- concatenate the new combination into string
v_output_combination:=FND_FLEX_EXT.concatenate_segments(v_number_of_segments,v_output_array,p_delimiter);

-- convert the string to CCID
v_new_account:=FND_FLEX_EXT.get_ccid('SQLGL','GL#', v_coa_id,fnd_date.date_to_canonical(sysdate),v_output_combination);

return v_new_account;


EXCEPTION

When others then

-- in case of failure return the original account

v_new_account:=p_CCID;

return v_new_account;

END switch_CCID_segment;

END XX_CCID;
/


Very simple function that can save tons of time.

No comments:

Post a Comment