EBS 中如何自定义ABC编制(ABC Compile)
(版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处;否则请与本人联系,违者必究)
ABC编制的定义过程如下
1. 通过Form来定义ABC Compile 头。
2. 点击Compile按钮来提交‘Compile ABC analysis’Request来生成ABC Compile分录并更新ABC编制头。
3. 点击菜单中的Print Compile来提交‘ABC descending value report’Request生成报表。
在第一步中只是定义了ABC 编制的头,包括Criterion,和编制的范围和计算值的范围等信息,全部都是指定好的用来生成ABC编制分录用的,没有什么可以特别自定义的。
对于第三步,它只是格式化ABC编制分录中的数据,并利用分录中的数据来生成报表,所以也没什么特别要自定义的部分。
对于第二步,往往用户可能会有特殊的需求,比如说我只想对某一种类型的事务来统计ABC 编制,那么就需要自定义了,但是生成ABC编制分录的Concurrent Request是可执行文件,不好来替换啥的,但可以根据SQL TRACE文件看出其中的逻辑和使用的SQL语句,其基本原理是
1. 检查ABC编制是不是有Assignment Group,如果有就报错。
2. 根据不同的Criterion来执行不同的SQL来插入ABC编制分录。
3. 对于数量为0的物料也要插入到ABC编制分录中。
4. 为ABC分录更新序列号,累积编制数量和累积编制价值。
5. 为ABC编制头更新物料数量,累积编制数量和累积编制价值等。
所以如果要自定义ABC编制的话,如果添加下面的第三步:
1. 通过Form来定义ABC Compile 头。
2. 点击Compile按钮来提交‘Compile ABC analysis’Request来生成ABC Compile分录并更新ABC编制头。
3. 运行PL/SQL来删除已有的ABC编制分录,并根据自己的需要重新生成ABC编制分录。
4. 点击菜单中的Print Compile来提交‘ABC descending value report’Request生成报表。
那么这个第三步中的PL/SQL应该要处理下面的所有事情,除了之前写的那些事情还要删除之前生成的分录,基本步骤如下:
1. 检查ABC编制是不是有Assignment Group,如果有就报错。
2. 删除已有的ABC编制分录
3. 根据不同的Criterion来执行不同的SQL(已添加自己需要的条件或者调整)来插入ABC编制分录。
4. 对于数量为0的物料也要插入到ABC编制分录中。
5. 为ABC分录更新序列号,累积编制数量和累积编制价值。
6. 为ABC编制头更新物料数量,累积编制数量和累积编制价值等。
下面的脚本是针对Historical usage value 的Criterion的脚本,可以指明对某一种或几种事物类型来生成ABC编制分录。
declare
l_abc_compile_id number :=&compile_id;
l_abc_group_count number :=0;
l_item_scope number :=0;
l_compile_type number :=0;
l_sec_inventory VARCHAR2(20);
l_org_id number;
l_start_date date;
l_end_date date;
l_compile_value number :=0;
l_compile_qty number:=0;
l_compile_rowid VARCHAR2(50);
l_cumulative_compile_value number :=0;
l_cumulative_compile_qty number :=0;
l_seq number :=0;
l_last_update_by number :=-1;
l_last_login number :=-1;
l_transaction_type_id number :=&transaction_type_id;
CURSOR updateSeq IS
SELECT ANAL.COMPILE_VALUE,
ANAL.COMPILE_QUANTITY,
ANAL.ROWID
FROM MTL_SYSTEM_ITEMS ITEM,
MTL_ABC_COMPILES ANAL
WHERE ANAL.ORGANIZATION_ID = l_org_id
AND ANAL.COMPILE_ID = l_abc_compile_id
AND ITEM.ORGANIZATION_ID = l_org_id
AND ANAL.INVENTORY_ITEM_ID = ITEM.INVENTORY_ITEM_ID
ORDER BY ANAL.COMPILE_VALUE DESC,
ITEM.SEGMENT1 ASC,
ITEM.SEGMENT2 ASC,
ITEM.SEGMENT3 ASC
FOR UPDATE OF ANAL.SEQUENCE_NUMBER,
ANAL.CUMULATIVE_VALUE,
ANAL.CUMULATIVE_QUANTITY;
begin
select count(1)
into l_abc_group_count
from MTL_ABC_ASSIGNMENT_GROUPS
where compile_id=l_abc_compile_id;
if l_abc_group_count = 0 then
delete MTL_ABC_COMPILES
where compile_id = l_abc_compile_id;
dbms_output.put_line('delete MTL_ABC_COMPILES successfully');
SELECT compile_type,item_scope_code, SECONDARY_INVENTORY,organization_id,start_date,cutoff_date,LAST_UPDATED_BY, -1
into l_compile_type, l_item_scope, l_sec_inventory, l_org_id, l_start_date, l_end_date, l_last_update_by,l_last_login
FROM MTL_ABC_COMPILE_HEADERS mach
WHERE compile_id = l_abc_compile_id;
dbms_output.put_line('compile_type:'||l_compile_type||',l_item_scope:'||l_item_scope||',l_sec_inventory:'||l_sec_inventory||',COMPILE_ID:'||l_abc_compile_id||',ORGANIZATION_ID:'||l_org_id);
if l_compile_type = 3 then
IF l_item_scope = 1 THEN
IF l_sec_inventory IS NULL THEN
INSERT INTO MTL_ABC_COMPILES (
COMPILE_ID,
INVENTORY_TYPE,
ORGANIZATION_ID,
INVENTORY_ITEM_ID,
SEQUENCE_NUMBER,
CREATION_DATE,
CREATED_BY,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_LOGIN,
COMPILE_QUANTITY,
COMPILE_VALUE)
SELECT
l_abc_compile_id,
'1',
l_org_id,
INVENTORY_ITEM_ID,
'0',
SYSDATE,
l_last_update_by,
SYSDATE,
l_last_update_by,
l_last_login,
SUM(ABS(PRIMARY_QUANTITY)),
SUM(ABS(NVL(PRIMARY_QUANTITY,0))*NVL(ACTUAL_COST,0) )
FROM MTL_MATERIAL_TRANSACTIONS
WHERE TRANSACTION_TYPE_ID <> 90
AND TRANSACTION_TYPE_ID = l_transaction_type_id
AND TRANSACTION_ACTION_ID <> 24
AND INVENTORY_ITEM_ID <> -1
AND ORGANIZATION_ID = l_org_id
AND transaction_date >= l_start_date
AND transaction_date <= l_end_date
GROUP BY INVENTORY_ITEM_ID;
--load zero item
INSERT INTO MTL_ABC_COMPILES
( INVENTORY_ITEM_ID,
ORGANIZATION_ID,
INVENTORY_TYPE,
COMPILE_ID,
LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN,
CREATION_DATE, CREATED_BY,
COMPILE_QUANTITY,
COMPILE_VALUE )
SELECT
/*+ INDEX(ITEM MTL_SYSTEM_ITEMS_U1) */
INVENTORY_ITEM_ID,
l_org_id,
1,
l_abc_compile_id,
SYSDATE,
l_last_update_by,
l_last_login,
SYSDATE,
l_last_update_by,
0,
0
FROM MTL_SYSTEM_ITEMS ITEM
WHERE ITEM.ORGANIZATION_ID = l_org_id
AND ITEM.STOCK_ENABLED_FLAG = 'Y'
AND NOT EXISTS
( SELECT 'X'
FROM MTL_ABC_COMPILES
WHERE INVENTORY_ITEM_ID = ITEM.INVENTORY_ITEM_ID
AND ORGANIZATION_ID = l_org_id
AND COMPILE_ID = l_abc_compile_id );
ELSE
INSERT INTO MTL_ABC_COMPILES (
COMPILE_ID,
INVENTORY_TYPE,
ORGANIZATION_ID,
INVENTORY_ITEM_ID,
SEQUENCE_NUMBER,
CREATION_DATE,
CREATED_BY,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_LOGIN,
COMPILE_QUANTITY,
COMPILE_VALUE)
SELECT
l_abc_compile_id,
'1',
l_org_id,
INVENTORY_ITEM_ID,
'0',
SYSDATE,
l_last_update_by,
SYSDATE,
l_last_update_by,
l_last_login,
SUM(ABS(PRIMARY_QUANTITY)),
SUM(ABS(NVL(PRIMARY_QUANTITY,0))*NVL(ACTUAL_COST,0) )
FROM MTL_MATERIAL_TRANSACTIONS
WHERE TRANSACTION_TYPE_ID <> 90
AND TRANSACTION_TYPE_ID = l_transaction_type_id
AND TRANSACTION_ACTION_ID <> 24
AND INVENTORY_ITEM_ID <> -1
AND ORGANIZATION_ID = l_org_id
AND transaction_date >= l_start_date
AND transaction_date <= l_end_date
AND INVENTORY_ITEM_ID IN ( SELECT SUB.INVENTORY_ITEM_ID
FROM MTL_ITEM_SUB_INVENTORIES SUB
WHERE SUB.ORGANIZATION_ID = l_org_id
AND SUB.SECONDARY_INVENTORY =l_sec_inventory)
GROUP BY INVENTORY_ITEM_ID;
--load zero item
INSERT INTO MTL_ABC_COMPILES
( ORGANIZATION_ID,
INVENTORY_ITEM_ID,
INVENTORY_TYPE,
COMPILE_ID,
LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN,
CREATION_DATE, CREATED_BY,
COMPILE_QUANTITY,
COMPILE_VALUE )
SELECT
/*+ INDEX(SUB MTL_ITEM_SUB_INVENTORIES_U2) INDEX(ITEM MTL_SYSTEM_ITEMS_U1) */
l_org_id,
ITEM.INVENTORY_ITEM_ID,
1,
l_abc_compile_id,
SYSDATE,
l_last_update_by,
l_last_login,
SYSDATE,
l_last_update_by,
0,
0
FROM MTL_SYSTEM_ITEMS ITEM,
MTL_ITEM_SUB_INVENTORIES SUB
WHERE ITEM.ORGANIZATION_ID = l_org_id
AND SUB.ORGANIZATION_ID = l_org_id
AND ITEM.INVENTORY_ITEM_ID = SUB.INVENTORY_ITEM_ID
AND SUB.SECONDARY_INVENTORY = l_sec_inventory
AND ITEM.STOCK_ENABLED_FLAG = 'Y'
AND NOT EXISTS
( SELECT 'X'
FROM MTL_ABC_COMPILES ABC
WHERE ABC.INVENTORY_ITEM_ID = ITEM.INVENTORY_ITEM_ID
AND ABC.ORGANIZATION_ID = l_org_id
AND ABC.COMPILE_ID = l_abc_compile_id )
GROUP BY ITEM.ORGANIZATION_ID, ITEM.INVENTORY_ITEM_ID;
END IF;
ELSE
INSERT INTO MTL_ABC_COMPILES (
COMPILE_ID,
INVENTORY_TYPE,
ORGANIZATION_ID,
INVENTORY_ITEM_ID,
SEQUENCE_NUMBER,
CREATION_DATE,
CREATED_BY,
LAST_UPDATE_DATE,
LAST_UPDATED_BY,
LAST_UPDATE_LOGIN,
COMPILE_QUANTITY,
COMPILE_VALUE)
SELECT
l_abc_compile_id,
'1',
l_org_id,
INVENTORY_ITEM_ID,
'0',
SYSDATE,
l_last_update_by,
SYSDATE,
l_last_update_by,
l_last_login,
SUM(ABS(PRIMARY_QUANTITY)),
SUM(ABS(NVL(PRIMARY_QUANTITY,0))*NVL(ACTUAL_COST,0) )
FROM MTL_MATERIAL_TRANSACTIONS
WHERE TRANSACTION_TYPE_ID <> 90
AND TRANSACTION_TYPE_ID = l_transaction_type_id
AND TRANSACTION_ACTION_ID <> 24
AND INVENTORY_ITEM_ID <> -1
AND ORGANIZATION_ID = l_org_id
AND transaction_date >= l_start_date
AND transaction_date <= l_end_date
AND SUBINVENTORY_CODE = l_sec_inventory
GROUP BY INVENTORY_ITEM_ID;
--load zero qty
INSERT INTO MTL_ABC_COMPILES
( ORGANIZATION_ID,
INVENTORY_ITEM_ID,
INVENTORY_TYPE,
COMPILE_ID,
LAST_UPDATE_DATE, LAST_UPDATED_BY, LAST_UPDATE_LOGIN,
CREATION_DATE, CREATED_BY,
COMPILE_QUANTITY,
COMPILE_VALUE )
SELECT
/*+ INDEX(SUB MTL_ITEM_SUB_INVENTORIES_U2) INDEX(ITEM MTL_SYSTEM_ITEMS_U1) */
l_org_id,
ITEM.INVENTORY_ITEM_ID,
1,
l_abc_compile_id,
SYSDATE,
l_last_update_by,
l_last_login,
SYSDATE,
l_last_update_by,
0,
0
FROM MTL_SYSTEM_ITEMS ITEM,
MTL_ITEM_SUB_INVENTORIES SUB
WHERE ITEM.ORGANIZATION_ID = l_org_id
AND SUB.ORGANIZATION_ID = l_org_id
AND ITEM.INVENTORY_ITEM_ID = SUB.INVENTORY_ITEM_ID
AND SUB.SECONDARY_INVENTORY = l_sec_inventory
AND ITEM.STOCK_ENABLED_FLAG = 'Y'
AND NOT EXISTS
( SELECT 'X'
FROM MTL_ABC_COMPILES ABC
WHERE ABC.INVENTORY_ITEM_ID = ITEM.INVENTORY_ITEM_ID
AND ABC.ORGANIZATION_ID = l_org_id
AND ABC.COMPILE_ID = l_abc_compile_id );
END IF;
--load seq number;
open updateSeq;
Loop
fetch updateSeq into l_compile_value, l_compile_qty , l_compile_rowid;
exit when updateSeq%notfound;
l_seq :=l_seq +1;
l_cumulative_compile_value :=l_cumulative_compile_value+l_compile_value;
l_cumulative_compile_qty :=l_cumulative_compile_qty + l_compile_qty;
UPDATE MTL_ABC_COMPILES
SET SEQUENCE_NUMBER = l_seq,
CUMULATIVE_VALUE = l_cumulative_compile_value,
CUMULATIVE_QUANTITY = l_cumulative_compile_qty
WHERE ROWID = l_compile_rowid;
end loop;
close updateSeq;
--update compile header
UPDATE MTL_ABC_COMPILE_HEADERS
SET COMPILE_ITEMS =
( SELECT COUNT(*)
FROM MTL_ABC_COMPILES
WHERE COMPILE_ID = l_abc_compile_id
AND ORGANIZATION_ID = l_org_id ),
CUMULATIVE_VALUE =
( SELECT SUM (COMPILE_VALUE)
FROM MTL_ABC_COMPILES
WHERE COMPILE_ID = l_abc_compile_id
AND ORGANIZATION_ID = l_org_id ),
CUMULATIVE_QUANTITY =
( SELECT SUM (COMPILE_QUANTITY)
FROM MTL_ABC_COMPILES
WHERE COMPILE_ID = l_abc_compile_id
AND ORGANIZATION_ID = l_org_id ),
LAST_UPDATE_DATE = SYSDATE,
LAST_UPDATED_BY = l_last_update_by,
COMPILE_DATE = SYSDATE
WHERE COMPILE_ID = l_abc_compile_id
AND ORGANIZATION_ID = l_org_id;
else
dbms_output.put_line('incorrect compile type');
end if;
else
dbms_output.put_line('there is abc group assignment');
end if;
end;
示例如下
1. ABC编制头定义如下
2. 点击Compile这个时候的ABC编制头如下
3. 点击Print Compile生成的‘ABC descending value report’报表如下
4. 运行脚本并指定事物类型为,更新后的ABC编制头如下
5. 重新生成的‘ABC descending valuereport’报表如下