IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing (#1277)

* IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing

* IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing

* IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing

- Fix rounding error
This commit is contained in:
hengsin 2022-05-12 17:12:05 +08:00 committed by GitHub
parent cfb4ebe785
commit a41aeb2205
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1365 additions and 67 deletions

View File

@ -0,0 +1,89 @@
SELECT register_migration_script('202203290700_IDEMPIERE-5057.sql') FROM dual
;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Mar 28, 2022 3:27:22 PM MYT
-- IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing
INSERT INTO AD_Element (AD_Element_ID,ColumnName,Updated,Name,PrintName,AD_Element_UU,IsActive,Created,CreatedBy,UpdatedBy,AD_Client_ID,EntityType,AD_Org_ID) VALUES (203283,'TaxPostingIndicator',TO_DATE('2022-03-28 15:27:21','YYYY-MM-DD HH24:MI:SS'),'Posting Indicator','Posting Indicator','6de750b3-2872-44ba-a78b-94fa6af96acf','Y',TO_DATE('2022-03-28 15:27:21','YYYY-MM-DD HH24:MI:SS'),100,100,0,'D',0)
;
-- Mar 28, 2022 3:32:00 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200160,'C_Tax Posting Indicator','429065e5-80c4-458e-a7ae-d20761dcb5a8','N','L',TO_DATE('2022-03-28 15:31:59','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_DATE('2022-03-28 15:31:59','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Mar 28, 2022 3:35:42 PM MYT
INSERT INTO AD_Ref_List (AD_Ref_List_ID,Description,AD_Ref_List_UU,Name,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,Updated,EntityType,AD_Reference_ID,Value,AD_Org_ID) VALUES (200446,'Tax is calculated on the full amount of the item and posted separately.','e84b618c-a8b3-47cf-89a6-dd674e52d3e4','Separate Tax Posting','Y',100,100,0,TO_DATE('2022-03-28 15:35:41','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2022-03-28 15:35:41','YYYY-MM-DD HH24:MI:SS'),'D',200160,'0',0)
;
-- Mar 28, 2022 3:37:59 PM MYT
INSERT INTO AD_Ref_List (AD_Ref_List_ID,Description,AD_Ref_List_UU,Name,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,Updated,EntityType,AD_Reference_ID,Value,AD_Org_ID) VALUES (200447,'Tax amount is added to the item amount during account posting time and for updating of Product Cost.','3e8e0d29-29ac-4c67-ae2c-92c0ee43d2e6','Distribute Tax with Relevant Expense','Y',100,100,0,TO_DATE('2022-03-28 15:37:58','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2022-03-28 15:37:58','YYYY-MM-DD HH24:MI:SS'),'D',200160,'1',0)
;
-- Mar 28, 2022 3:38:05 PM MYT
UPDATE AD_Reference SET IsOrderByValue='Y',Updated=TO_DATE('2022-03-28 15:38:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Reference_ID=200160
;
-- Mar 28, 2022 3:42:45 PM MYT
INSERT INTO AD_Column (AD_Column_ID,SeqNoSelection,IsSyncDatabase,Version,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,IsKey,ReadOnlyLogic,IsAutocomplete,IsAllowLogging,MandatoryLogic,AD_Column_UU,Updated,IsUpdateable,ColumnName,DefaultValue,Name,IsAllowCopy,IsActive,CreatedBy,UpdatedBy,IsAlwaysUpdateable,AD_Client_ID,Created,EntityType,IsEncrypted,IsSecure,FKConstraintType,AD_Element_ID,AD_Reference_Value_ID,AD_Table_ID,AD_Reference_ID,IsToolbarButton,AD_Org_ID,IsHtml) VALUES (213805,0,'N',0,'N','N','N',0,'N',1,'N','N','@IsSummary@=Y','N','Y','@IsSummary@=N','e7a97d28-f550-4253-a77b-b6fab1e7b38a',TO_DATE('2022-03-28 15:42:44','YYYY-MM-DD HH24:MI:SS'),'Y','TaxPostingIndicator','0','Posting Indicator','Y','Y',100,100,'N',0,TO_DATE('2022-03-28 15:42:44','YYYY-MM-DD HH24:MI:SS'),'D','N','N','N',203283,200160,261,17,'N',0,'N')
;
-- Mar 28, 2022 3:42:52 PM MYT
INSERT INTO AD_TreeNode (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNode_UU) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 200012, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='TL' AND t.AD_Table_ID=282 AND NOT EXISTS (SELECT * FROM AD_TreeNode e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200012)
;
-- Mar 28, 2022 3:42:53 PM MYT
ALTER TABLE C_Tax ADD TaxPostingIndicator CHAR(1) DEFAULT '0'
;
-- Mar 28, 2022 3:55:05 PM MYT
INSERT INTO AD_Field (SortNo,AD_Field_ID,IsEncrypted,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,IsReadOnly,DisplayLogic,Updated,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,CreatedBy,UpdatedBy,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,Created,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,EntityType,AD_Tab_ID,AD_Org_ID) VALUES (0,205862,'N',0,'N','N',1010,'Y','N','@IsDocumentLevel@=N',TO_DATE('2022-03-28 15:55:04','YYYY-MM-DD HH24:MI:SS'),'Posting Indicator','96a2af5a-4a6f-4d44-ab54-da4713d70fc5','Y','N',100,100,'Y','Y',1010,4,'N',0,TO_DATE('2022-03-28 15:55:04','YYYY-MM-DD HH24:MI:SS'),2,1,'N','N',213805,'D',174,0)
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=180,SeqNoGrid=180,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=190,SeqNoGrid=190,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=203325
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=200,SeqNoGrid=200,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=203326
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=210,SeqNoGrid=210,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=974
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=220,SeqNoGrid=220,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=976
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=230,SeqNoGrid=230,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=975
;
UPDATE AD_Field SET SeqNo=240,SeqNoGrid=240,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=977
;
UPDATE AD_Field SET SeqNo=250,SeqNoGrid=250,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=202402
;
-- Mar 28, 2022 3:56:15 PM MYT
UPDATE AD_Column SET ReadOnlyLogic='@IsDocumentLevel@=Y', MandatoryLogic='@IsDocumentLevel@=N',Updated=TO_DATE('2022-03-28 15:56:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213805
;
-- Mar 28, 2022 6:43:36 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsDocumentLevel@=N & @IsSummary@=N', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2022-03-28 18:43:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 8:10:21 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsDocumentLevel@=N & @IsSummary@=N & @SOPOType@!S', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2022-03-28 20:10:21','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 8:10:34 PM MYT
INSERT INTO AD_TreeNode (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNode_UU) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 200014, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='TL' AND t.AD_Table_ID=282 AND NOT EXISTS (SELECT * FROM AD_TreeNode e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200014)
;

View File

@ -0,0 +1,36 @@
-- IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing
SELECT register_migration_script('202204011738_IDEMPIERE-5057.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Element SET Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.',Updated=TO_TIMESTAMP('2022-04-01 17:38:03','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=203283
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Column SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Process_Para SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', AD_Element_ID=203283 WHERE UPPER(ColumnName)='TAXPOSTINGINDICATOR' AND IsCentrallyMaintained='Y' AND AD_Element_ID IS NULL
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Process_Para SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283 AND IsCentrallyMaintained='Y'
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_InfoColumn SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283 AND IsCentrallyMaintained='Y'
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Field SET Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Column_ID IN (SELECT AD_Column_ID FROM AD_Column WHERE AD_Element_ID=203283) AND IsCentrallyMaintained='Y'
;

View File

@ -0,0 +1,87 @@
SELECT register_migration_script('202203290700_IDEMPIERE-5057.sql') FROM dual
;
-- Mar 28, 2022 3:27:22 PM MYT
-- IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing
INSERT INTO AD_Element (AD_Element_ID,ColumnName,Updated,Name,PrintName,AD_Element_UU,IsActive,Created,CreatedBy,UpdatedBy,AD_Client_ID,EntityType,AD_Org_ID) VALUES (203283,'TaxPostingIndicator',TO_TIMESTAMP('2022-03-28 15:27:21','YYYY-MM-DD HH24:MI:SS'),'Posting Indicator','Posting Indicator','6de750b3-2872-44ba-a78b-94fa6af96acf','Y',TO_TIMESTAMP('2022-03-28 15:27:21','YYYY-MM-DD HH24:MI:SS'),100,100,0,'D',0)
;
-- Mar 28, 2022 3:32:00 PM MYT
INSERT INTO AD_Reference (AD_Reference_ID,Name,AD_Reference_UU,IsOrderByValue,ValidationType,Updated,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,EntityType,AD_Org_ID) VALUES (200160,'C_Tax Posting Indicator','429065e5-80c4-458e-a7ae-d20761dcb5a8','N','L',TO_TIMESTAMP('2022-03-28 15:31:59','YYYY-MM-DD HH24:MI:SS'),'Y',100,100,0,TO_TIMESTAMP('2022-03-28 15:31:59','YYYY-MM-DD HH24:MI:SS'),'D',0)
;
-- Mar 28, 2022 3:35:42 PM MYT
INSERT INTO AD_Ref_List (AD_Ref_List_ID,Description,AD_Ref_List_UU,Name,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,Updated,EntityType,AD_Reference_ID,Value,AD_Org_ID) VALUES (200446,'Tax is calculated on the full amount of the item and posted separately.','e84b618c-a8b3-47cf-89a6-dd674e52d3e4','Separate Tax Posting','Y',100,100,0,TO_TIMESTAMP('2022-03-28 15:35:41','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-28 15:35:41','YYYY-MM-DD HH24:MI:SS'),'D',200160,'0',0)
;
-- Mar 28, 2022 3:37:59 PM MYT
INSERT INTO AD_Ref_List (AD_Ref_List_ID,Description,AD_Ref_List_UU,Name,IsActive,CreatedBy,UpdatedBy,AD_Client_ID,Created,Updated,EntityType,AD_Reference_ID,Value,AD_Org_ID) VALUES (200447,'Tax amount is added to the item amount during account posting time and for updating of Product Cost.','3e8e0d29-29ac-4c67-ae2c-92c0ee43d2e6','Distribute Tax with Relevant Expense','Y',100,100,0,TO_TIMESTAMP('2022-03-28 15:37:58','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-28 15:37:58','YYYY-MM-DD HH24:MI:SS'),'D',200160,'1',0)
;
-- Mar 28, 2022 3:38:05 PM MYT
UPDATE AD_Reference SET IsOrderByValue='Y',Updated=TO_TIMESTAMP('2022-03-28 15:38:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Reference_ID=200160
;
-- Mar 28, 2022 3:42:45 PM MYT
INSERT INTO AD_Column (AD_Column_ID,SeqNoSelection,IsSyncDatabase,Version,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,IsKey,ReadOnlyLogic,IsAutocomplete,IsAllowLogging,MandatoryLogic,AD_Column_UU,Updated,IsUpdateable,ColumnName,DefaultValue,Name,IsAllowCopy,IsActive,CreatedBy,UpdatedBy,IsAlwaysUpdateable,AD_Client_ID,Created,EntityType,IsEncrypted,IsSecure,FKConstraintType,AD_Element_ID,AD_Reference_Value_ID,AD_Table_ID,AD_Reference_ID,IsToolbarButton,AD_Org_ID,IsHtml) VALUES (213805,0,'N',0,'N','N','N',0,'N',1,'N','N','@IsSummary@=Y','N','Y','@IsSummary@=N','e7a97d28-f550-4253-a77b-b6fab1e7b38a',TO_TIMESTAMP('2022-03-28 15:42:44','YYYY-MM-DD HH24:MI:SS'),'Y','TaxPostingIndicator','0','Posting Indicator','Y','Y',100,100,'N',0,TO_TIMESTAMP('2022-03-28 15:42:44','YYYY-MM-DD HH24:MI:SS'),'D','N','N','N',203283,200160,261,17,'N',0,'N')
;
-- Mar 28, 2022 3:42:52 PM MYT
INSERT INTO AD_TreeNode (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNode_UU) SELECT t.AD_Client_ID, 0, 'Y', statement_timestamp(), 100, statement_timestamp(), 100,t.AD_Tree_ID, 200012, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='TL' AND t.AD_Table_ID=282 AND NOT EXISTS (SELECT * FROM AD_TreeNode e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200012)
;
-- Mar 28, 2022 3:42:53 PM MYT
ALTER TABLE C_Tax ADD COLUMN TaxPostingIndicator CHAR(1) DEFAULT '0'
;
-- Mar 28, 2022 3:55:05 PM MYT
INSERT INTO AD_Field (SortNo,AD_Field_ID,IsEncrypted,DisplayLength,IsSameLine,IsHeading,SeqNo,IsCentrallyMaintained,IsReadOnly,DisplayLogic,Updated,Name,AD_Field_UU,IsDisplayed,IsFieldOnly,CreatedBy,UpdatedBy,IsActive,IsDisplayedGrid,SeqNoGrid,XPosition,IsQuickEntry,AD_Client_ID,Created,ColumnSpan,NumLines,IsAdvancedField,IsDefaultFocus,AD_Column_ID,EntityType,AD_Tab_ID,AD_Org_ID) VALUES (0,205862,'N',0,'N','N',1010,'Y','N','@IsDocumentLevel@=N',TO_TIMESTAMP('2022-03-28 15:55:04','YYYY-MM-DD HH24:MI:SS'),'Posting Indicator','96a2af5a-4a6f-4d44-ab54-da4713d70fc5','Y','N',100,100,'Y','Y',1010,4,'N',0,TO_TIMESTAMP('2022-03-28 15:55:04','YYYY-MM-DD HH24:MI:SS'),2,1,'N','N',213805,'D',174,0)
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=180,SeqNoGrid=180,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=190,SeqNoGrid=190,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=203325
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=200,SeqNoGrid=200,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=203326
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=210,SeqNoGrid=210,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=974
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=220,SeqNoGrid=220,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=976
;
-- Mar 28, 2022 3:55:33 PM MYT
UPDATE AD_Field SET SeqNo=230,SeqNoGrid=230,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=975
;
UPDATE AD_Field SET SeqNo=240,SeqNoGrid=240,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=977
;
UPDATE AD_Field SET SeqNo=250,SeqNoGrid=250,IsDisplayed='Y', Updated=Now(), UpdatedBy=100 WHERE AD_Field_ID=202402
;
-- Mar 28, 2022 3:56:15 PM MYT
UPDATE AD_Column SET ReadOnlyLogic='@IsDocumentLevel@=Y', MandatoryLogic='@IsDocumentLevel@=N',Updated=TO_TIMESTAMP('2022-03-28 15:56:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=213805
;
-- Mar 28, 2022 6:43:36 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsDocumentLevel@=N & @IsSummary@=N', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2022-03-28 18:43:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 8:10:21 PM MYT
UPDATE AD_Field SET DisplayLogic='@IsDocumentLevel@=N & @IsSummary@=N & @SOPOType@!S', AD_Val_Rule_ID=NULL, AD_Reference_Value_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2022-03-28 20:10:21','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=205862
;
-- Mar 28, 2022 8:10:34 PM MYT
INSERT INTO AD_TreeNode (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNode_UU) SELECT t.AD_Client_ID, 0, 'Y', statement_timestamp(), 100, statement_timestamp(), 100,t.AD_Tree_ID, 200014, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='TL' AND t.AD_Table_ID=282 AND NOT EXISTS (SELECT * FROM AD_TreeNode e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200014)
;

View File

@ -0,0 +1,33 @@
-- IDEMPIERE-5057 Implement Deductible and non deductible input tax for purchasing and costing
SELECT register_migration_script('202204011738_IDEMPIERE-5057.sql') FROM dual;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Element SET Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.',Updated=TO_TIMESTAMP('2022-04-01 17:38:03','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=203283
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Column SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Process_Para SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', AD_Element_ID=203283 WHERE UPPER(ColumnName)='TAXPOSTINGINDICATOR' AND IsCentrallyMaintained='Y' AND AD_Element_ID IS NULL
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Process_Para SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283 AND IsCentrallyMaintained='Y'
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_InfoColumn SET ColumnName='TaxPostingIndicator', Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Element_ID=203283 AND IsCentrallyMaintained='Y'
;
-- Apr 1, 2022, 5:38:03 PM MYT
UPDATE AD_Field SET Name='Posting Indicator', Description='Type of input tax (deductible and non deductible)', Help='Separate Tax Posting: Tax is calculated on the full amount of the item and posted separately.
Distribute Tax with Relevant Expense: Tax amount is added to the item amount during account posting time and for updating of Product Cost.', Placeholder=NULL WHERE AD_Column_ID IN (SELECT AD_Column_ID FROM AD_Column WHERE AD_Element_ID=203283) AND IsCentrallyMaintained='Y'
;

View File

@ -31,30 +31,112 @@ import org.compiere.process.ProcessInfo;
*/ */
public interface ITaxProvider { public interface ITaxProvider {
/**
* Calculate order tax
* @param provider
* @param order
* @return true if success, false otherwise
*/
public boolean calculateOrderTaxTotal(MTaxProvider provider, MOrder order); public boolean calculateOrderTaxTotal(MTaxProvider provider, MOrder order);
/**
* Update order tax for line
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateOrderTax(MTaxProvider provider, MOrderLine line); public boolean updateOrderTax(MTaxProvider provider, MOrderLine line);
/**
* Re-calculate order tax for line (if line tax id change)
* @param provider
* @param line
* @param newRecord
* @return true if success, false otherwise
*/
public boolean recalculateTax(MTaxProvider provider, MOrderLine line, boolean newRecord); public boolean recalculateTax(MTaxProvider provider, MOrderLine line, boolean newRecord);
/**
* Update order tax total
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateHeaderTax(MTaxProvider provider, MOrderLine line); public boolean updateHeaderTax(MTaxProvider provider, MOrderLine line);
/**
* Calculate invoice tax total
* @param provider
* @param invoice
* @return true if success, false otherwise
*/
public boolean calculateInvoiceTaxTotal(MTaxProvider provider, MInvoice invoice); public boolean calculateInvoiceTaxTotal(MTaxProvider provider, MInvoice invoice);
/**
* Update invoice tax for line
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateInvoiceTax(MTaxProvider provider, MInvoiceLine line); public boolean updateInvoiceTax(MTaxProvider provider, MInvoiceLine line);
/**
* Re-calculate invoice tax for line (if line tax id change)
* @param provider
* @param line
* @param newRecord
* @return true if success, false otherwise
*/
public boolean recalculateTax(MTaxProvider provider, MInvoiceLine line, boolean newRecord); public boolean recalculateTax(MTaxProvider provider, MInvoiceLine line, boolean newRecord);
/**
* Update invoice tax total
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateHeaderTax(MTaxProvider provider, MInvoiceLine line); public boolean updateHeaderTax(MTaxProvider provider, MInvoiceLine line);
/**
* Calculate rma tax total
* @param provider
* @param rma
* @return true if success, false otherwise
*/
public boolean calculateRMATaxTotal(MTaxProvider provider, MRMA rma); public boolean calculateRMATaxTotal(MTaxProvider provider, MRMA rma);
/**
* Update rma tax for rma line
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateRMATax(MTaxProvider provider, MRMALine line); public boolean updateRMATax(MTaxProvider provider, MRMALine line);
/**
* Re-calculate rma tax for ram line (if line tax id change)
* @param provider
* @param line
* @param newRecord
* @return true if success, false otherwise
*/
public boolean recalculateTax(MTaxProvider provider, MRMALine line, boolean newRecord); public boolean recalculateTax(MTaxProvider provider, MRMALine line, boolean newRecord);
/**
* Update rma header total
* @param provider
* @param line
* @return true if success, false otherwise
*/
public boolean updateHeaderTax(MTaxProvider provider, MRMALine line); public boolean updateHeaderTax(MTaxProvider provider, MRMALine line);
/**
*
* @param provider
* @param pi
* @return error message
* @throws Exception
*/
public String validateConnection(MTaxProvider provider, ProcessInfo pi) throws Exception; public String validateConnection(MTaxProvider provider, ProcessInfo pi) throws Exception;
} }

View File

@ -20,6 +20,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.compiere.model.I_C_OrderLine; import org.compiere.model.I_C_OrderLine;
@ -616,9 +617,57 @@ public class Doc_InOut extends Doc
int stdPrecision = MCurrency.getStdPrecision(getCtx(), C_Currency_ID); int stdPrecision = MCurrency.getStdPrecision(getCtx(), C_Currency_ID);
BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision); BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision);
if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax);
costs = costs.subtract(costTax); if(tax.isSummary())
{
MTax[] cTaxes = tax.getChildTaxes(false);
List<MTax> toSubtract = new ArrayList<>();
for(MTax cTax : cTaxes)
{
if (!cTax.isDistributeTaxWithLineItem())
toSubtract.add(cTax);
}
if (toSubtract.size() > 0)
{
BigDecimal base = costs.subtract(costTax);
for(MTax cTax : toSubtract)
{
BigDecimal ts = cTax.calculateTax(base, false, stdPrecision);
costs = costs.subtract(ts);
}
}
}
else if (!tax.isDistributeTaxWithLineItem())
{
costs = costs.subtract(costTax);
}
} }
} // correct included Tax } // correct included Tax
else if (C_Tax_ID != 0)
{
MTax tax = MTax.get(getCtx(), C_Tax_ID);
if(tax.isSummary())
{
MTax[] cTaxes = tax.getChildTaxes(false);
BigDecimal base = costs;
for(MTax cTax : cTaxes)
{
if (cTax.isDistributeTaxWithLineItem())
{
//do not round to stdprecision before multiply qty
BigDecimal costTax = cTax.calculateTax(base, false, 12);
if (log.isLoggable(Level.FINE)) log.fine("Costs=" + base + " - Tax=" + costTax);
costs = costs.add(costTax);
}
}
}
else if (tax.isDistributeTaxWithLineItem())
{
//do not round to stdprecision before multiply qty
BigDecimal costTax = tax.calculateTax(costs, false, 12);
if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax);
costs = costs.add(costTax);
}
}
} }
costs = costs.multiply(line.getQty()); costs = costs.multiply(line.getQty());
} }
@ -781,18 +830,50 @@ public class Doc_InOut extends Doc
MOrderLine originalOrderLine = (MOrderLine) originalInOutLine.getC_OrderLine(); MOrderLine originalOrderLine = (MOrderLine) originalInOutLine.getC_OrderLine();
// Goodwill: Correct included Tax // Goodwill: Correct included Tax
int C_Tax_ID = originalOrderLine.getC_Tax_ID(); int C_Tax_ID = originalOrderLine.getC_Tax_ID();
MTax tax = MTax.get(getCtx(), C_Tax_ID);
int stdPrecision = MCurrency.getStdPrecision(getCtx(), originalOrderLine.getC_Currency_ID());
if (originalOrderLine.isTaxIncluded() && C_Tax_ID != 0) if (originalOrderLine.isTaxIncluded() && C_Tax_ID != 0)
{ {
MTax tax = MTax.get(getCtx(), C_Tax_ID); BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision);
if (!tax.isZeroTax()) if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax);
if (tax.isSummary())
{
costs = costs.subtract(costTax);
BigDecimal base = costs;
for(MTax cTax : tax.getChildTaxes(false))
{
if (!cTax.isZeroTax() && cTax.isDistributeTaxWithLineItem())
{
costTax = cTax.calculateTax(base, false, stdPrecision);
costs = costs.add(costTax);
}
}
}
else if (!tax.isZeroTax() && !tax.isDistributeTaxWithLineItem())
{ {
int stdPrecision = MCurrency.getStdPrecision(getCtx(), originalOrderLine.getC_Currency_ID());
BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision);
if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax);
costs = costs.subtract(costTax); costs = costs.subtract(costTax);
} }
} // correct included Tax } // correct included Tax
else
{
if (tax.isSummary())
{
BigDecimal base = costs;
for(MTax cTax : tax.getChildTaxes(false))
{
if (!cTax.isZeroTax() && cTax.isDistributeTaxWithLineItem())
{
BigDecimal costTax = cTax.calculateTax(base, false, stdPrecision);
costs = costs.add(costTax);
}
}
}
else if (tax.isDistributeTaxWithLineItem())
{
BigDecimal costTax = tax.calculateTax(costs, false, stdPrecision);
costs = costs.add(costTax);
}
}
// different currency // different currency
if (C_Currency_ID != originalOrderLine.getC_Currency_ID()) if (C_Currency_ID != originalOrderLine.getC_Currency_ID())
{ {

View File

@ -74,6 +74,9 @@ public class Doc_Invoice extends Doc
/** Contained Optional Tax Lines */ /** Contained Optional Tax Lines */
protected DocTax[] m_taxes = null; protected DocTax[] m_taxes = null;
/** Contained Optional Tax Lines Distributed to Line Item */
@SuppressWarnings("unused")
private DocTax[] m_addToLineTaxes = null;
/** Currency Precision */ /** Currency Precision */
protected int m_precision = -1; protected int m_precision = -1;
/** All lines are Service */ /** All lines are Service */
@ -109,6 +112,7 @@ public class Doc_Invoice extends Doc
private DocTax[] loadTaxes() private DocTax[] loadTaxes()
{ {
ArrayList<DocTax> list = new ArrayList<DocTax>(); ArrayList<DocTax> list = new ArrayList<DocTax>();
ArrayList<DocTax> distributeList = new ArrayList<DocTax>();
String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax " String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax "
+ "FROM C_Tax t, C_InvoiceTax it " + "FROM C_Tax t, C_InvoiceTax it "
+ "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Invoice_ID=?"; + "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Invoice_ID=?";
@ -129,10 +133,18 @@ public class Doc_Invoice extends Doc
BigDecimal amount = rs.getBigDecimal(5); BigDecimal amount = rs.getBigDecimal(5);
boolean salesTax = "Y".equals(rs.getString(6)); boolean salesTax = "Y".equals(rs.getString(6));
// //
MTax tax = MTax.get(getCtx(), C_Tax_ID);
DocTax taxLine = new DocTax(C_Tax_ID, name, rate, DocTax taxLine = new DocTax(C_Tax_ID, name, rate,
taxBaseAmt, amount, salesTax); taxBaseAmt, amount, salesTax);
if (log.isLoggable(Level.FINE)) log.fine(taxLine.toString()); if (log.isLoggable(Level.FINE)) log.fine(taxLine.toString());
list.add(taxLine); if (!tax.isDistributeTaxWithLineItem())
{
list.add(taxLine);
}
else
{
distributeList.add(taxLine);
}
} }
} }
catch (SQLException e) catch (SQLException e)
@ -148,6 +160,9 @@ public class Doc_Invoice extends Doc
// Return Array // Return Array
DocTax[] tl = new DocTax[list.size()]; DocTax[] tl = new DocTax[list.size()];
list.toArray(tl); list.toArray(tl);
// Distribute list
m_addToLineTaxes = distributeList.toArray(new DocTax[0]);
return tl; return tl;
} // loadTaxes } // loadTaxes
@ -184,24 +199,33 @@ public class Doc_Invoice extends Doc
{ {
BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, getStdPrecision()); BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, getStdPrecision());
if (log.isLoggable(Level.FINE)) log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax); if (log.isLoggable(Level.FINE)) log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax);
LineNetAmt = LineNetAmt.subtract(LineNetAmtTax);
if (tax.isSummary()) { if (tax.isSummary()) {
LineNetAmt = LineNetAmt.subtract(LineNetAmtTax);
BigDecimal base = LineNetAmt;
BigDecimal sumChildLineNetAmtTax = Env.ZERO; BigDecimal sumChildLineNetAmtTax = Env.ZERO;
DocTax taxToApplyDiff = null; DocTax taxToApplyDiff = null;
for (MTax childTax : tax.getChildTaxes(false)) { for (MTax childTax : tax.getChildTaxes(false)) {
if (!childTax.isZeroTax()) if (!childTax.isZeroTax())
{ {
BigDecimal childLineNetAmtTax = childTax.calculateTax(LineNetAmt, false, getStdPrecision()); BigDecimal childLineNetAmtTax = childTax.calculateTax(base, false, getStdPrecision());
if (log.isLoggable(Level.FINE)) log.fine("LineNetAmt=" + LineNetAmt + " - Child Tax=" + childLineNetAmtTax); if (log.isLoggable(Level.FINE)) log.fine("LineNetAmt=" + base + " - Child Tax=" + childLineNetAmtTax);
for (int t = 0; t < m_taxes.length; t++) if (childTax.isDistributeTaxWithLineItem())
{
LineNetAmt = LineNetAmt.add(childLineNetAmtTax);
LineNetAmtTax = LineNetAmtTax.subtract(childLineNetAmtTax);
}
else
{ {
if (m_taxes[t].getC_Tax_ID() == childTax.getC_Tax_ID()) for (int t = 0; t < m_taxes.length; t++)
{ {
m_taxes[t].addIncludedTax(childLineNetAmtTax); if (m_taxes[t].getC_Tax_ID() == childTax.getC_Tax_ID())
taxToApplyDiff = m_taxes[t]; {
sumChildLineNetAmtTax = sumChildLineNetAmtTax.add(childLineNetAmtTax); m_taxes[t].addIncludedTax(childLineNetAmtTax);
break; taxToApplyDiff = m_taxes[t];
sumChildLineNetAmtTax = sumChildLineNetAmtTax.add(childLineNetAmtTax);
break;
}
} }
} }
} }
@ -211,12 +235,16 @@ public class Doc_Invoice extends Doc
taxToApplyDiff.addIncludedTax(diffChildVsSummary); taxToApplyDiff.addIncludedTax(diffChildVsSummary);
} }
} else { } else {
for (int t = 0; t < m_taxes.length; t++) if (!tax.isDistributeTaxWithLineItem())
{ {
if (m_taxes[t].getC_Tax_ID() == C_Tax_ID) LineNetAmt = LineNetAmt.subtract(LineNetAmtTax);
for (int t = 0; t < m_taxes.length; t++)
{ {
m_taxes[t].addIncludedTax(LineNetAmtTax); if (m_taxes[t].getC_Tax_ID() == C_Tax_ID)
break; {
m_taxes[t].addIncludedTax(LineNetAmtTax);
break;
}
} }
} }
} }
@ -225,6 +253,29 @@ public class Doc_Invoice extends Doc
PriceList = PriceList.subtract(PriceListTax); PriceList = PriceList.subtract(PriceListTax);
} }
} // correct included Tax } // correct included Tax
else
{
int stdPrecision = MCurrency.getStdPrecision(getCtx(), invoice.getC_Currency_ID());
MTax tax = MTax.get(getCtx(), C_Tax_ID);
if (tax.isSummary())
{
MTax[] cTaxes = tax.getChildTaxes(false);
BigDecimal base = LineNetAmt;
for(MTax cTax : cTaxes)
{
if (cTax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = cTax.calculateTax(base, false, stdPrecision);
LineNetAmt = LineNetAmt.add(taxAmt);
}
}
}
else if (tax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = tax.calculateTax(LineNetAmt, false, stdPrecision);
LineNetAmt = LineNetAmt.add(taxAmt);
}
}
docLine.setAmount (LineNetAmt, PriceList, Qty); // qty for discount calc docLine.setAmount (LineNetAmt, PriceList, Qty); // qty for discount calc
if (docLine.isItem()) if (docLine.isItem())

View File

@ -37,6 +37,7 @@ import org.compiere.model.MAcctSchema;
import org.compiere.model.MAcctSchemaElement; import org.compiere.model.MAcctSchemaElement;
import org.compiere.model.MConversionRate; import org.compiere.model.MConversionRate;
import org.compiere.model.MCostDetail; import org.compiere.model.MCostDetail;
import org.compiere.model.MCurrency;
import org.compiere.model.MFactAcct; import org.compiere.model.MFactAcct;
import org.compiere.model.MInOut; import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine; import org.compiere.model.MInOutLine;
@ -44,6 +45,7 @@ import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine; import org.compiere.model.MInvoiceLine;
import org.compiere.model.MMatchInv; import org.compiere.model.MMatchInv;
import org.compiere.model.MOrderLandedCostAllocation; import org.compiere.model.MOrderLandedCostAllocation;
import org.compiere.model.MTax;
import org.compiere.model.MUOM; import org.compiere.model.MUOM;
import org.compiere.model.ProductCost; import org.compiere.model.ProductCost;
import org.compiere.model.Query; import org.compiere.model.Query;
@ -533,6 +535,56 @@ public class Doc_MatchInv extends Doc
} }
} }
tAmt = tAmt.add(LineNetAmt); //Invoice Price tAmt = tAmt.add(LineNetAmt); //Invoice Price
// adjust for tax
MTax tax = MTax.get(getCtx(), m_invoiceLine.getC_Tax_ID());
int stdPrecision = MCurrency.getStdPrecision(getCtx(), m_invoiceLine.getParent().getC_Currency_ID());
if (m_invoiceLine.isTaxIncluded())
{
BigDecimal tAmtTax = tax.calculateTax(tAmt, true, stdPrecision);
if (tax.isSummary())
{
tAmt = tAmt.subtract(tAmtTax);
BigDecimal base = tAmt;
for (MTax childTax : tax.getChildTaxes(false))
{
if (!childTax.isZeroTax())
{
if (childTax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = childTax.calculateTax(base, false, stdPrecision);
tAmt = tAmt.add(taxAmt);
}
}
}
}
else if (!tax.isDistributeTaxWithLineItem())
{
tAmt = tAmt.subtract(tAmtTax);
}
}
else
{
if (tax.isSummary())
{
BigDecimal base = tAmt;
for (MTax childTax : tax.getChildTaxes(false))
{
if (!childTax.isZeroTax())
{
if (childTax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = childTax.calculateTax(base, false, stdPrecision);
tAmt = tAmt.add(taxAmt);
}
}
}
}
else if (tax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = tax.calculateTax(tAmt, false, stdPrecision);
tAmt = tAmt.add(taxAmt);
}
}
// Different currency // Different currency
MInvoice invoice = m_invoiceLine.getParent(); MInvoice invoice = m_invoiceLine.getParent();

View File

@ -286,17 +286,53 @@ public class Doc_MatchPO extends Doc
poCost = m_oLine.getPriceActual(); poCost = m_oLine.getPriceActual();
// Goodwill: Correct included Tax // Goodwill: Correct included Tax
int C_Tax_ID = m_oLine.getC_Tax_ID(); int C_Tax_ID = m_oLine.getC_Tax_ID();
MTax tax = MTax.get(getCtx(), C_Tax_ID);
int stdPrecision = MCurrency.getStdPrecision(getCtx(), m_oLine.getC_Currency_ID());
if (m_oLine.isTaxIncluded() && C_Tax_ID != 0) if (m_oLine.isTaxIncluded() && C_Tax_ID != 0)
{ {
MTax tax = MTax.get(getCtx(), C_Tax_ID);
if (!tax.isZeroTax()) if (!tax.isZeroTax())
{ {
int stdPrecision = MCurrency.getStdPrecision(getCtx(), m_oLine.getC_Currency_ID());
BigDecimal costTax = tax.calculateTax(poCost, true, stdPrecision); BigDecimal costTax = tax.calculateTax(poCost, true, stdPrecision);
if (log.isLoggable(Level.FINE)) log.fine("Costs=" + poCost + " - Tax=" + costTax); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + poCost + " - Tax=" + costTax);
poCost = poCost.subtract(costTax); if (tax.isSummary())
{
poCost = poCost.subtract(costTax);
BigDecimal base = poCost;
for (MTax childTax : tax.getChildTaxes(false))
{
if (!childTax.isZeroTax() && childTax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = childTax.calculateTax(base, false, stdPrecision);
poCost = poCost.add(taxAmt);
}
}
}
else if (!tax.isDistributeTaxWithLineItem())
{
poCost = poCost.subtract(costTax);
}
} }
} // correct included Tax } // correct included Tax
else
{
if (tax.isSummary())
{
BigDecimal base = poCost;
for (MTax childTax : tax.getChildTaxes(false))
{
if (childTax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = childTax.calculateTax(base, false, stdPrecision);
poCost = poCost.add(taxAmt);
}
}
}
else if (tax.isDistributeTaxWithLineItem())
{
BigDecimal taxAmt = tax.calculateTax(poCost, false, stdPrecision);
poCost = poCost.add(taxAmt);
}
}
} }
MInOutLine receiptLine = new MInOutLine (getCtx(), m_M_InOutLine_ID, getTrxName()); MInOutLine receiptLine = new MInOutLine (getCtx(), m_M_InOutLine_ID, getTrxName());
@ -383,7 +419,7 @@ public class Doc_MatchPO extends Doc
if (MAcctSchema.COSTINGMETHOD_StandardCosting.equals(costingMethod)) if (MAcctSchema.COSTINGMETHOD_StandardCosting.equals(costingMethod))
{ {
if (m_matchPO.getReversal_ID() > 0) if (m_matchPO.isReversal())
{ {
// Product PPV // Product PPV
FactLine cr = fact.createLine(null, FactLine cr = fact.createLine(null,
@ -582,7 +618,7 @@ public class Doc_MatchPO extends Doc
tAmt = tAmt.add(isReturnTrx ? poCost.negate() : poCost); tAmt = tAmt.add(isReturnTrx ? poCost.negate() : poCost);
tQty = tQty.add(isReturnTrx ? getQty().negate() : getQty()); tQty = tQty.add(isReturnTrx ? getQty().negate() : getQty());
if (mMatchPO.getReversal_ID() > 0) if (mMatchPO.isReversal())
{ {
String error = createLandedCostAdjustments(as, landedCostMap, mMatchPO, tQty); String error = createLandedCostAdjustments(as, landedCostMap, mMatchPO, tQty);
if (!Util.isEmpty(error)) if (!Util.isEmpty(error))
@ -601,7 +637,7 @@ public class Doc_MatchPO extends Doc
return "SaveError"; return "SaveError";
} }
if (mMatchPO.getReversal_ID() <= 0) if (!mMatchPO.isReversal())
{ {
String error = createLandedCostAdjustments(as, landedCostMap, mMatchPO, tQty); String error = createLandedCostAdjustments(as, landedCostMap, mMatchPO, tQty);
if (!Util.isEmpty(error)) if (!Util.isEmpty(error))

View File

@ -22,7 +22,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Interface for C_Tax /** Generated Interface for C_Tax
* @author iDempiere (generated) * @author iDempiere (generated)
* @version Release 9 * @version Release 10
*/ */
public interface I_C_Tax public interface I_C_Tax
{ {
@ -44,8 +44,8 @@ public interface I_C_Tax
/** Column name AD_Client_ID */ /** Column name AD_Client_ID */
public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID"; public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID";
/** Get Client. /** Get Tenant.
* Client/Tenant for this installation. * Tenant for this installation.
*/ */
public int getAD_Client_ID(); public int getAD_Client_ID();
@ -53,12 +53,12 @@ public interface I_C_Tax
public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID"; public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID";
/** Set Organization. /** Set Organization.
* Organizational entity within client * Organizational entity within tenant
*/ */
public void setAD_Org_ID (int AD_Org_ID); public void setAD_Org_ID (int AD_Org_ID);
/** Get Organization. /** Get Organization.
* Organizational entity within client * Organizational entity within tenant
*/ */
public int getAD_Org_ID(); public int getAD_Org_ID();
@ -358,6 +358,15 @@ public interface I_C_Tax
*/ */
public String getTaxIndicator(); public String getTaxIndicator();
/** Column name TaxPostingIndicator */
public static final String COLUMNNAME_TaxPostingIndicator = "TaxPostingIndicator";
/** Set Posting Indicator */
public void setTaxPostingIndicator (String TaxPostingIndicator);
/** Get Posting Indicator */
public String getTaxPostingIndicator();
/** Column name To_Country_ID */ /** Column name To_Country_ID */
public static final String COLUMNNAME_To_Country_ID = "To_Country_ID"; public static final String COLUMNNAME_To_Country_ID = "To_Country_ID";

View File

@ -943,14 +943,49 @@ public class MInvoiceLine extends X_C_InvoiceLine
* author teo_sarca [ 1583825 ] * author teo_sarca [ 1583825 ]
*/ */
protected boolean updateInvoiceTax(boolean oldTax) { protected boolean updateInvoiceTax(boolean oldTax) {
MInvoiceTax tax = MInvoiceTax.get (this, getPrecision(), oldTax, get_TrxName()); int C_Tax_ID = getC_Tax_ID();
if (tax != null) { boolean isOldTax = oldTax && is_ValueChanged(MInvoiceTax.COLUMNNAME_C_Tax_ID);
if (!tax.calculateTaxFromLines()) if (isOldTax)
return false; {
Object old = get_ValueOld(MInvoiceTax.COLUMNNAME_C_Tax_ID);
if (old == null)
{
return true;
}
C_Tax_ID = ((Integer)old).intValue();
}
if (C_Tax_ID == 0)
{
return true;
}
// red1 - solving BUGS #[ 1701331 ] , #[ 1786103 ] MTax t = MTax.get(C_Tax_ID);
if (!tax.save(get_TrxName())) if (t.isSummary())
return false; {
MInvoiceTax[] invoiceTaxes = MInvoiceTax.getChildTaxes(this, getPrecision(), oldTax, get_TrxName());
if (invoiceTaxes != null && invoiceTaxes.length > 0)
{
for(MInvoiceTax tax : invoiceTaxes)
{
if (!tax.calculateTaxFromLines())
return false;
if (!tax.save(get_TrxName()))
return false;
}
}
}
else
{
MInvoiceTax tax = MInvoiceTax.get (this, getPrecision(), oldTax, get_TrxName());
if (tax != null) {
if (!tax.calculateTaxFromLines())
return false;
// red1 - solving BUGS #[ 1701331 ] , #[ 1786103 ]
if (!tax.save(get_TrxName()))
return false;
}
} }
return true; return true;
} }

View File

@ -20,6 +20,8 @@ import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
@ -104,6 +106,74 @@ public class MInvoiceTax extends X_C_InvoiceTax
return retValue; return retValue;
} // get } // get
/**
* Get Child Tax Lines for Invoice Line
* @param line invoice line
* @param precision currency precision
* @param oldTax if true old tax is returned
* @param trxName transaction name
* @return existing or new tax
*/
public static MInvoiceTax[] getChildTaxes(MInvoiceLine line, int precision,
boolean oldTax, String trxName)
{
List<MInvoiceTax> invoiceTaxes = new ArrayList<MInvoiceTax>();
if (line == null || line.getC_Invoice_ID() == 0)
return invoiceTaxes.toArray(new MInvoiceTax[0]);
int C_Tax_ID = line.getC_Tax_ID();
if (oldTax)
{
Object old = line.get_ValueOld(MInvoiceLine.COLUMNNAME_C_Tax_ID);
if (old == null)
return invoiceTaxes.toArray(new MInvoiceTax[0]);
C_Tax_ID = ((Integer)old).intValue();
}
if (C_Tax_ID == 0)
{
return invoiceTaxes.toArray(new MInvoiceTax[0]);
}
MTax tax = MTax.get(C_Tax_ID);
if (!tax.isSummary())
return invoiceTaxes.toArray(new MInvoiceTax[0]);
MTax[] cTaxes = tax.getChildTaxes(false);
for(MTax cTax : cTaxes) {
MInvoiceTax invoiceTax = new Query(line.getCtx(), Table_Name, "C_Invoice_ID=? AND C_Tax_ID=?", trxName)
.setParameters(line.getC_Invoice_ID(), cTax.getC_Tax_ID())
.firstOnly();
if (invoiceTax != null)
{
invoiceTax.set_TrxName(trxName);
invoiceTax.setPrecision(precision);
invoiceTaxes.add(invoiceTax);
}
// If the old tax was required and there is no MInvoiceTax for that
// return null, and not create another MInvoiceTax - teo_sarca [ 1583825 ]
else
{
if (oldTax)
continue;
}
if (invoiceTax == null)
{
// Create New
invoiceTax = new MInvoiceTax(line.getCtx(), 0, trxName);
invoiceTax.set_TrxName(trxName);
invoiceTax.setClientOrg(line);
invoiceTax.setC_Invoice_ID(line.getC_Invoice_ID());
invoiceTax.setC_Tax_ID(line.getC_Tax_ID());
invoiceTax.setPrecision(precision);
invoiceTax.setIsTaxIncluded(line.isTaxIncluded());
invoiceTaxes.add(invoiceTax);
}
}
return invoiceTaxes.toArray(new MInvoiceTax[0]);
}
/** Static Logger */ /** Static Logger */
private static CLogger s_log = CLogger.getCLogger (MInvoiceTax.class); private static CLogger s_log = CLogger.getCLogger (MInvoiceTax.class);

View File

@ -1422,4 +1422,16 @@ public class MMatchPO extends X_M_MatchPO
} }
return false; return false;
} }
/**
* @return true if this is created to reverse another match po document
*/
public boolean isReversal() {
if (getReversal_ID() > 0) {
MMatchPO reversal = new MMatchPO (getCtx(), getReversal_ID(), get_TrxName());
if (reversal.getM_MatchPO_ID() < getM_MatchPO_ID())
return true;
}
return false;
}
} // MMatchPO } // MMatchPO

View File

@ -980,17 +980,57 @@ public class MOrderLine extends X_C_OrderLine
* author teo_sarca [ 1583825 ] * author teo_sarca [ 1583825 ]
*/ */
public boolean updateOrderTax(boolean oldTax) { public boolean updateOrderTax(boolean oldTax) {
MOrderTax tax = MOrderTax.get (this, getPrecision(), oldTax, get_TrxName()); int C_Tax_ID = getC_Tax_ID();
if (tax != null) { boolean isOldTax = oldTax && is_ValueChanged(MOrderLine.COLUMNNAME_C_Tax_ID);
if (!tax.calculateTaxFromLines()) if (isOldTax)
return false; {
if (tax.getTaxAmt().signum() != 0) { Object old = get_ValueOld(MOrderLine.COLUMNNAME_C_Tax_ID);
if (!tax.save(get_TrxName())) if (old == null)
return false; {
return true;
} }
else { C_Tax_ID = ((Integer)old).intValue();
if (!tax.is_new() && !tax.delete(false, get_TrxName())) }
if (C_Tax_ID == 0)
{
return true;
}
MTax t = MTax.get(C_Tax_ID);
if (t.isSummary())
{
MOrderTax[] taxes = MOrderTax.getChildTaxes(this, getPrecision(), isOldTax, get_TrxName());
if (taxes != null && taxes.length > 0)
{
for(MOrderTax tax : taxes)
{
if (!tax.calculateTaxFromLines())
return false;
if (tax.getTaxAmt().signum() != 0) {
if (!tax.save(get_TrxName()))
return false;
}
else {
if (!tax.is_new() && !tax.delete(false, get_TrxName()))
return false;
}
}
}
}
else
{
MOrderTax tax = MOrderTax.get (this, getPrecision(), oldTax, get_TrxName());
if (tax != null) {
if (!tax.calculateTaxFromLines())
return false; return false;
if (tax.getTaxAmt().signum() != 0) {
if (!tax.save(get_TrxName()))
return false;
}
else {
if (!tax.is_new() && !tax.delete(false, get_TrxName()))
return false;
}
} }
} }
return true; return true;

View File

@ -19,6 +19,8 @@ package org.compiere.model;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
@ -124,6 +126,99 @@ public class MOrderTax extends X_C_OrderTax
return retValue; return retValue;
} // get } // get
/**
* Get Child Tax Line for Order Line
* @param line Order line
* @param precision currency precision
* @param oldTax get old tax
* @param trxName transaction
* @return existing or new tax
*/
public static MOrderTax[] getChildTaxes(MOrderLine line, int precision,
boolean oldTax, String trxName)
{
List<MOrderTax> orderTaxes = new ArrayList<MOrderTax>();
if (line == null || line.getC_Order_ID() == 0)
{
return orderTaxes.toArray(new MOrderTax[0]);
}
int C_Tax_ID = line.getC_Tax_ID();
if (oldTax)
{
Object old = line.get_ValueOld(MOrderTax.COLUMNNAME_C_Tax_ID);
if (old == null)
{
return orderTaxes.toArray(new MOrderTax[0]);
}
C_Tax_ID = ((Integer)old).intValue();
}
if (C_Tax_ID == 0)
{
return orderTaxes.toArray(new MOrderTax[0]);
}
MTax tax = MTax.get(C_Tax_ID);
if (!tax.isSummary())
return orderTaxes.toArray(new MOrderTax[0]);
MTax[] cTaxes = tax.getChildTaxes(false);
for(MTax cTax : cTaxes) {
MOrderTax orderTax = null;
String sql = "SELECT * FROM C_OrderTax WHERE C_Order_ID=? AND C_Tax_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
pstmt.setInt (1, line.getC_Order_ID());
pstmt.setInt (2, cTax.getC_Tax_ID());
rs = pstmt.executeQuery ();
if (rs.next ())
orderTax = new MOrderTax (line.getCtx(), rs, trxName);
}
catch (Exception e)
{
s_log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
if (orderTax != null)
{
orderTax.setPrecision(precision);
orderTax.set_TrxName(trxName);
orderTaxes.add(orderTax);
}
// If the old tax was required and there is no MOrderTax for that
// return null, and not create another MOrderTax - teo_sarca [ 1583825 ]
else
{
if (oldTax)
continue;
}
if (orderTax == null)
{
// Create New
orderTax = new MOrderTax(line.getCtx(), 0, trxName);
orderTax.set_TrxName(trxName);
orderTax.setClientOrg(line);
orderTax.setC_Order_ID(line.getC_Order_ID());
orderTax.setC_Tax_ID(line.getC_Tax_ID());
orderTax.setPrecision(precision);
orderTax.setIsTaxIncluded(line.isTaxIncluded());
orderTaxes.add(orderTax);
}
}
return orderTaxes.toArray(new MOrderTax[0]);
}
/** Static Logger */ /** Static Logger */
private static CLogger s_log = CLogger.getCLogger (MOrderTax.class); private static CLogger s_log = CLogger.getCLogger (MOrderTax.class);

View File

@ -378,22 +378,69 @@ public class MRMALine extends X_M_RMALine
return true; return true;
} }
/**
*
* @param oldTax true if the old C_Tax_ID should be used
* @return true if success, false otherwise
*/
protected boolean updateOrderTax(boolean oldTax) protected boolean updateOrderTax(boolean oldTax)
{ {
MRMATax tax = MRMATax.get (this, getPrecision(), oldTax, get_TrxName()); int C_Tax_ID = getC_Tax_ID();
if (tax != null) boolean isOldTax = oldTax && is_ValueChanged(MRMALine.COLUMNNAME_C_Tax_ID);
if (isOldTax)
{ {
if (!tax.calculateTaxFromLines()) Object old = get_ValueOld(MRMALine.COLUMNNAME_C_Tax_ID);
return false; if (old == null)
if (tax.getTaxAmt().signum() != 0)
{ {
if (!tax.save(get_TrxName())) return true;
return false;
} }
else C_Tax_ID = ((Integer)old).intValue();
}
if (C_Tax_ID == 0)
{
return true;
}
MTax t = MTax.get(C_Tax_ID);
if (t.isSummary())
{
MRMATax[] taxes = MRMATax.getChildTaxes(this, getPrecision(), oldTax, get_TrxName());
if (taxes != null && taxes.length > 0)
{ {
if (!tax.is_new() && !tax.delete(false, get_TrxName())) for(MRMATax tax : taxes)
{
if (!tax.calculateTaxFromLines())
return false;
if (tax.getTaxAmt().signum() != 0)
{
if (!tax.save(get_TrxName()))
return false;
}
else
{
if (!tax.is_new() && !tax.delete(false, get_TrxName()))
return false;
}
}
}
}
else
{
MRMATax tax = MRMATax.get (this, getPrecision(), oldTax, get_TrxName());
if (tax != null)
{
if (!tax.calculateTaxFromLines())
return false; return false;
if (tax.getTaxAmt().signum() != 0)
{
if (!tax.save(get_TrxName()))
return false;
}
else
{
if (!tax.is_new() && !tax.delete(false, get_TrxName()))
return false;
}
} }
} }
return true; return true;

View File

@ -16,6 +16,8 @@ package org.compiere.model;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
@ -118,6 +120,96 @@ public class MRMATax extends X_M_RMATax
return retValue; return retValue;
} }
/**
* Get Child Tax Lines for RMA Line
* @param line RMA line
* @param precision currency precision
* @param oldTax get old tax
* @param trxName transaction
* @return existing or new tax
*/
public static MRMATax[] getChildTaxes(MRMALine line, int precision,
boolean oldTax, String trxName)
{
List<MRMATax> rmaTaxes = new ArrayList<MRMATax>();
if (line == null || line.getM_RMA_ID() == 0)
{
return rmaTaxes.toArray(new MRMATax[0]);
}
int C_Tax_ID = line.getC_Tax_ID();
if (oldTax)
{
Object old = line.get_ValueOld(MRMATax.COLUMNNAME_C_Tax_ID);
if (old == null)
{
return rmaTaxes.toArray(new MRMATax[0]);
}
C_Tax_ID = ((Integer)old).intValue();
}
if (C_Tax_ID == 0)
{
return rmaTaxes.toArray(new MRMATax[0]);
}
MTax tax = MTax.get(C_Tax_ID);
if (!tax.isSummary())
return rmaTaxes.toArray(new MRMATax[0]);
MTax[] cTaxes = tax.getChildTaxes(false);
for(MTax cTax : cTaxes) {
MRMATax rmaTax = null;
String sql = "SELECT * FROM M_RMATax WHERE M_RMA_ID=? AND C_Tax_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
pstmt.setInt (1, line.getM_RMA_ID());
pstmt.setInt (2, cTax.getC_Tax_ID());
rs = pstmt.executeQuery ();
if (rs.next ())
rmaTax = new MRMATax (line.getCtx(), rs, trxName);
}
catch (Exception e)
{
s_log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
if (rmaTax != null)
{
rmaTax.setPrecision(precision);
rmaTax.set_TrxName(trxName);
rmaTaxes.add(rmaTax);
}
// If the old tax was required and there is no MOrderTax for that
// return null, and not create another MOrderTax - teo_sarca [ 1583825 ]
else
{
if (oldTax)
continue;
}
if (rmaTax == null)
{
// Create New
rmaTax = new MRMATax(line.getCtx(), 0, trxName);
rmaTax.set_TrxName(trxName);
rmaTax.setClientOrg(line);
rmaTax.setM_RMA_ID(line.getM_RMA_ID());
rmaTax.setC_Tax_ID(line.getC_Tax_ID());
rmaTax.setPrecision(precision);
rmaTax.setIsTaxIncluded(line.getParent().isTaxIncluded());
rmaTaxes.add(rmaTax);
}
}
return rmaTaxes.toArray(new MRMATax[0]);
}
/** Static Logger */ /** Static Logger */
private static CLogger s_log = CLogger.getCLogger (MRMATax.class); private static CLogger s_log = CLogger.getCLogger (MRMATax.class);

View File

@ -411,4 +411,12 @@ public class MTax extends X_C_Tax implements ImmutablePOSupport
return this; return this;
} }
/**
*
* @return true if input tax is added to product cost
*/
public boolean isDistributeTaxWithLineItem()
{
return TAXPOSTINGINDICATOR_DistributeTaxWithRelevantExpense.equals(getTaxPostingIndicator());
}
} // MTax } // MTax

View File

@ -26,7 +26,7 @@ import org.compiere.util.KeyNamePair;
/** Generated Model for C_Tax /** Generated Model for C_Tax
* @author iDempiere (generated) * @author iDempiere (generated)
* @version Release 9 - $Id$ */ * @version Release 10 - $Id$ */
@org.adempiere.base.Model(table="C_Tax") @org.adempiere.base.Model(table="C_Tax")
public class X_C_Tax extends PO implements I_C_Tax, I_Persistent public class X_C_Tax extends PO implements I_C_Tax, I_Persistent
{ {
@ -34,7 +34,7 @@ public class X_C_Tax extends PO implements I_C_Tax, I_Persistent
/** /**
* *
*/ */
private static final long serialVersionUID = 20220116L; private static final long serialVersionUID = 20220329L;
/** Standard Constructor */ /** Standard Constructor */
public X_C_Tax (Properties ctx, int C_Tax_ID, String trxName) public X_C_Tax (Properties ctx, int C_Tax_ID, String trxName)
@ -599,6 +599,28 @@ public class X_C_Tax extends PO implements I_C_Tax, I_Persistent
return (String)get_Value(COLUMNNAME_TaxIndicator); return (String)get_Value(COLUMNNAME_TaxIndicator);
} }
/** TaxPostingIndicator AD_Reference_ID=200160 */
public static final int TAXPOSTINGINDICATOR_AD_Reference_ID=200160;
/** Separate Tax Posting = 0 */
public static final String TAXPOSTINGINDICATOR_SeparateTaxPosting = "0";
/** Distribute Tax with Relevant Expense = 1 */
public static final String TAXPOSTINGINDICATOR_DistributeTaxWithRelevantExpense = "1";
/** Set Posting Indicator.
@param TaxPostingIndicator Posting Indicator
*/
public void setTaxPostingIndicator (String TaxPostingIndicator)
{
set_Value (COLUMNNAME_TaxPostingIndicator, TaxPostingIndicator);
}
/** Get Posting Indicator.
@return Posting Indicator */
public String getTaxPostingIndicator()
{
return (String)get_Value(COLUMNNAME_TaxPostingIndicator);
}
/** Set To. /** Set To.
@param To_Country_ID Receiving Country @param To_Country_ID Receiving Country
*/ */

View File

@ -25,14 +25,44 @@
package org.idempiere.test.model; package org.idempiere.test.model;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.adempiere.base.Core; import org.adempiere.base.Core;
import org.compiere.model.MAccount;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MBPartner; import org.compiere.model.MBPartner;
import org.compiere.model.MClientInfo;
import org.compiere.model.MCost;
import org.compiere.model.MDocType;
import org.compiere.model.MFactAcct;
import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine;
import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MMatchPO;
import org.compiere.model.MOrder;
import org.compiere.model.MOrderLine;
import org.compiere.model.MPriceList;
import org.compiere.model.MPriceListVersion;
import org.compiere.model.MProduct;
import org.compiere.model.MProductPrice;
import org.compiere.model.MTax; import org.compiere.model.MTax;
import org.compiere.model.MTaxCategory;
import org.compiere.model.MWarehouse;
import org.compiere.model.ProductCost;
import org.compiere.model.Tax; import org.compiere.model.Tax;
import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine;
import org.compiere.process.ProcessInfo;
import org.compiere.util.CacheMgt;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.TimeUtil; import org.compiere.util.TimeUtil;
import org.compiere.wf.MWorkflow;
import org.idempiere.test.AbstractTestCase; import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -46,8 +76,11 @@ public class MTaxTest extends AbstractTestCase {
private static final int STANDARD_TAX_ID = 104; private static final int STANDARD_TAX_ID = 104;
private static final int STANDARD_TAX_CATEGORY_ID=107; private static final int STANDARD_TAX_CATEGORY_ID=107;
private final static int BP_JOE_BLOCK = 118; private static final int BP_JOE_BLOCK_ID = 118;
private static final int PRODUCT_MULCH = 137; private static final int PRODUCT_MULCH_ID = 137;
private static final int PURCHASE_PRICE_LIST_ID = 102;
private static final int BP_PATIO_ID = 121;
private static final int MM_RECEIPT_DOCTYPE_ID = 122;
public MTaxTest() { public MTaxTest() {
} }
@ -73,20 +106,308 @@ public class MTaxTest extends AbstractTestCase {
int taxExemptId = Tax.getExemptTax(Env.getCtx(), getAD_Org_ID(), getTrxName()); int taxExemptId = Tax.getExemptTax(Env.getCtx(), getAD_Org_ID(), getTrxName());
assertTrue(taxExemptId>0, "Fail to get tax exempt Id"); assertTrue(taxExemptId>0, "Fail to get tax exempt Id");
MBPartner bp = new MBPartner(Env.getCtx(), BP_JOE_BLOCK, getTrxName()); MBPartner bp = new MBPartner(Env.getCtx(), BP_JOE_BLOCK_ID, getTrxName());
bp.setIsTaxExempt(true); bp.setIsTaxExempt(true);
bp.saveEx(); bp.saveEx();
int id = Core.getTaxLookup().get(Env.getCtx(), PRODUCT_MULCH, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(), int id = Core.getTaxLookup().get(Env.getCtx(), PRODUCT_MULCH_ID, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(),
bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName()); bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName());
assertEquals(taxExemptId, id, "Unexpected tax id"); assertEquals(taxExemptId, id, "Unexpected tax id");
bp.setIsTaxExempt(false); bp.setIsTaxExempt(false);
bp.saveEx(); bp.saveEx();
id = Core.getTaxLookup().get(Env.getCtx(), PRODUCT_MULCH, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(), id = Core.getTaxLookup().get(Env.getCtx(), PRODUCT_MULCH_ID, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(),
bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName()); bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName());
assertTrue(id != taxExemptId, "Unexpected tax id: " + id); assertTrue(id != taxExemptId, "Unexpected tax id: " + id);
assertEquals(STANDARD_TAX_ID, id, "Unexpected tax id"); assertEquals(STANDARD_TAX_ID, id, "Unexpected tax id");
} }
@Test
public void testDistributeTaxToProductCost() {
MProduct product = null;
MTaxCategory category = null;
MTax tax = null;
try {
category = new MTaxCategory(Env.getCtx(), 0, null);
category.setName("testDistributeTaxToProductCost");
category.saveEx();
//need to create tax without trx as tax is cache
tax = new MTax(Env.getCtx(), 0, null);
tax.setC_TaxCategory_ID(category.get_ID());
tax.setIsDocumentLevel(false);
tax.setIsSummary(false);
tax.setRate(new BigDecimal("5.00"));
tax.setTaxPostingIndicator(MTax.TAXPOSTINGINDICATOR_DistributeTaxWithRelevantExpense);
tax.setSOPOType(MTax.SOPOTYPE_PurchaseTax);
tax.setName("testDistributeTaxToProductCost");
tax.saveEx();
CacheMgt.get().reset();
//need to create product with trx as order line get product from cache
MProduct p = MProduct.get(PRODUCT_MULCH_ID);
product = new MProduct(Env.getCtx(), 0, null);
product.setM_Product_Category_ID(p.getM_Product_Category_ID());
product.setC_TaxCategory_ID(category.get_ID());
product.setIsStocked(true);
product.setIsPurchased(true);
product.setIsSold(true);
product.setIsStocked(true);
product.setProductType(MProduct.PRODUCTTYPE_Item);
product.setName("testDistributeTaxToProductCost");
product.setC_UOM_ID(p.getC_UOM_ID());
product.saveEx();
MPriceList priceList = MPriceList.get(PURCHASE_PRICE_LIST_ID);
MPriceListVersion priceListVersion = priceList.getPriceListVersion(null);
MProductPrice productPrice = new MProductPrice(Env.getCtx(), 0, getTrxName());
productPrice.setM_PriceList_Version_ID(priceListVersion.get_ID());
productPrice.setM_Product_ID(product.getM_Product_ID());
productPrice.setPrices(new BigDecimal("2.00"), new BigDecimal("2.00"), new BigDecimal("2.00"));
productPrice.saveEx();
//purchase price of 2 + 5% tax
BigDecimal expectedCost = new BigDecimal("2.00").add(new BigDecimal("2.00").multiply(new BigDecimal("0.05"))).setScale(2, RoundingMode.HALF_EVEN);
MBPartner bpartner = MBPartner.get(Env.getCtx(), BP_PATIO_ID);
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
order.setBPartner(bpartner);
order.setIsSOTrx(false);
order.setC_DocTypeTarget_ID();
order.setDocStatus(DocAction.STATUS_Drafted);
order.setDocAction(DocAction.ACTION_Complete);
order.saveEx();
MOrderLine orderLine = new MOrderLine(order);
orderLine.setLine(10);
orderLine.setProduct(product);
orderLine.setQty(new BigDecimal("1"));
orderLine.setTax();
orderLine.saveEx();
assertEquals(tax.get_ID(), orderLine.getC_Tax_ID(), "Un-expected tax id");
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
order.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
assertEquals(expectedCost, order.getGrandTotal().setScale(2, RoundingMode.HALF_EVEN), "Un-expected order grand total");
MInOut receipt = new MInOut(order, MM_RECEIPT_DOCTYPE_ID, order.getDateOrdered()); // MM Receipt
receipt.saveEx();
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
MInOutLine receiptLine = new MInOutLine(receipt);
receiptLine.setOrderLine(orderLine, M_Locator_ID, new BigDecimal("1"));
receiptLine.setLine(10);
receiptLine.setQty(new BigDecimal("1"));
receiptLine.saveEx();
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
receipt.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
MInvoice invoice = new MInvoice(order, MDocType.getOfDocBaseType(Env.getCtx(), MDocType.DOCBASETYPE_APInvoice)[0].getC_DocType_ID(), order.getDateAcct());
invoice.setDocStatus(DocAction.STATUS_Drafted);
invoice.setDocAction(DocAction.ACTION_Complete);
invoice.saveEx();
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
invoiceLine.setShipLine(receiptLine);
invoiceLine.setLine(10);
invoiceLine.setProduct(product);
invoiceLine.setQty(new BigDecimal("1"));
invoiceLine.saveEx();
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
invoice.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
//ensure match po have been posted
MMatchPO[] matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
assertNotNull(matchPOs, "Can't retrive match po for order line");
assertEquals(1, matchPOs.length, "Un-expected number of match po record for order line");
if (!matchPOs[0].isPosted())
DocumentEngine.postImmediate(Env.getCtx(), getAD_Client_ID(), MMatchPO.Table_ID, matchPOs[0].get_ID(), true, getTrxName());
ProductCost productCost = new ProductCost(Env.getCtx(), product.get_ID(), 0, getTrxName());
productCost.setQty(new BigDecimal("1"));
MAcctSchema schema = MClientInfo.get().getMAcctSchema1();
BigDecimal averageCost = productCost.getProductCosts(schema, getAD_Org_ID(), MCost.COSTINGMETHOD_AveragePO, 0, true);
if (averageCost == null)
averageCost = BigDecimal.ZERO;
averageCost = averageCost.setScale(2, RoundingMode.HALF_EVEN);
assertEquals(expectedCost, averageCost, "Un-expected average cost");
MAccount acctAsset = productCost.getAccount(ProductCost.ACCTTYPE_P_Asset, schema);
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MInOut.Table_ID
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + receipt.get_ID()
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + schema.getC_AcctSchema_ID();
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
BigDecimal totalDebit = new BigDecimal("0.00");
for(int id : ids) {
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
if (fa.getAccount_ID() == acctAsset.getAccount_ID()) {
totalDebit = totalDebit.add(fa.getAmtAcctDr());
}
}
assertEquals(expectedCost, totalDebit.setScale(2, RoundingMode.HALF_EVEN), "Un-expected product asset account posted amount");
} finally {
rollback();
if (product != null && product.get_ID() > 0)
product.deleteEx(true);
if (tax != null && tax.get_ID() > 0)
tax.deleteEx(true);
if (category != null && category.get_ID() > 0)
category.deleteEx(true);
}
}
@Test
public void testSeparateTaxPosting() {
MProduct product = null;
MTaxCategory category = null;
MTax tax = null;
try {
category = new MTaxCategory(Env.getCtx(), 0, null);
category.setName("testSeparateTaxPosting");
category.saveEx();
//need to create tax without trx as tax is cache
tax = new MTax(Env.getCtx(), 0, null);
tax.setC_TaxCategory_ID(category.get_ID());
tax.setIsDocumentLevel(false);
tax.setIsSummary(false);
tax.setRate(new BigDecimal("5.00"));
tax.setTaxPostingIndicator(MTax.TAXPOSTINGINDICATOR_SeparateTaxPosting);
tax.setSOPOType(MTax.SOPOTYPE_PurchaseTax);
tax.setName("testSeparateTaxPosting");
tax.saveEx();
CacheMgt.get().reset();
//need to create product with trx as order line get product from cache
MProduct p = MProduct.get(PRODUCT_MULCH_ID);
product = new MProduct(Env.getCtx(), 0, null);
product.setM_Product_Category_ID(p.getM_Product_Category_ID());
product.setC_TaxCategory_ID(category.get_ID());
product.setIsStocked(true);
product.setIsPurchased(true);
product.setIsSold(true);
product.setIsStocked(true);
product.setProductType(MProduct.PRODUCTTYPE_Item);
product.setName("testSeparateTaxPosting");
product.setC_UOM_ID(p.getC_UOM_ID());
product.saveEx();
MPriceList priceList = MPriceList.get(PURCHASE_PRICE_LIST_ID);
MPriceListVersion priceListVersion = priceList.getPriceListVersion(null);
MProductPrice productPrice = new MProductPrice(Env.getCtx(), 0, getTrxName());
productPrice.setM_PriceList_Version_ID(priceListVersion.get_ID());
productPrice.setM_Product_ID(product.getM_Product_ID());
productPrice.setPrices(new BigDecimal("2.00"), new BigDecimal("2.00"), new BigDecimal("2.00"));
productPrice.saveEx();
//purchase price of 2
BigDecimal expectedCost = new BigDecimal("2.00").setScale(2, RoundingMode.HALF_EVEN);
//purchase price of 2 + 5% tax
BigDecimal expectedTotal = new BigDecimal("2.00").add(new BigDecimal("2.00").multiply(new BigDecimal("0.05"))).setScale(2, RoundingMode.HALF_EVEN);
MBPartner bpartner = MBPartner.get(Env.getCtx(), BP_PATIO_ID);
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
order.setBPartner(bpartner);
order.setIsSOTrx(false);
order.setC_DocTypeTarget_ID();
order.setDocStatus(DocAction.STATUS_Drafted);
order.setDocAction(DocAction.ACTION_Complete);
order.saveEx();
MOrderLine orderLine = new MOrderLine(order);
orderLine.setLine(10);
orderLine.setProduct(product);
orderLine.setQty(new BigDecimal("1"));
orderLine.setTax();
orderLine.saveEx();
assertEquals(tax.get_ID(), orderLine.getC_Tax_ID(), "Un-expected tax id");
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
order.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
assertEquals(expectedTotal, order.getGrandTotal().setScale(2, RoundingMode.HALF_EVEN), "Un-expected order grand total");
MInOut receipt = new MInOut(order, MM_RECEIPT_DOCTYPE_ID, order.getDateOrdered()); // MM Receipt
receipt.saveEx();
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
MInOutLine receiptLine = new MInOutLine(receipt);
receiptLine.setOrderLine(orderLine, M_Locator_ID, new BigDecimal("1"));
receiptLine.setLine(10);
receiptLine.setQty(new BigDecimal("1"));
receiptLine.saveEx();
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
receipt.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
MInvoice invoice = new MInvoice(order, MDocType.getOfDocBaseType(Env.getCtx(), MDocType.DOCBASETYPE_APInvoice)[0].getC_DocType_ID(), order.getDateAcct());
invoice.setDocStatus(DocAction.STATUS_Drafted);
invoice.setDocAction(DocAction.ACTION_Complete);
invoice.saveEx();
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
invoiceLine.setShipLine(receiptLine);
invoiceLine.setLine(10);
invoiceLine.setProduct(product);
invoiceLine.setQty(new BigDecimal("1"));
invoiceLine.saveEx();
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
invoice.load(getTrxName());
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
//ensure match po have been posted
MMatchPO[] matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
assertNotNull(matchPOs, "Can't retrive match po for order line");
assertEquals(1, matchPOs.length, "Un-expected number of match po record for order line");
if (!matchPOs[0].isPosted())
DocumentEngine.postImmediate(Env.getCtx(), getAD_Client_ID(), MMatchPO.Table_ID, matchPOs[0].get_ID(), true, getTrxName());
ProductCost productCost = new ProductCost(Env.getCtx(), product.get_ID(), 0, getTrxName());
productCost.setQty(new BigDecimal("1"));
MAcctSchema schema = MClientInfo.get().getMAcctSchema1();
BigDecimal averageCost = productCost.getProductCosts(schema, getAD_Org_ID(), MCost.COSTINGMETHOD_AveragePO, 0, true);
if (averageCost == null)
averageCost = BigDecimal.ZERO;
averageCost = averageCost.setScale(2, RoundingMode.HALF_EVEN);
assertEquals(expectedCost, averageCost, "Un-expected average cost");
MAccount acctAsset = productCost.getAccount(ProductCost.ACCTTYPE_P_Asset, schema);
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MInOut.Table_ID
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + receipt.get_ID()
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + schema.getC_AcctSchema_ID();
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
BigDecimal totalDebit = new BigDecimal("0.00");
for(int id : ids) {
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
if (fa.getAccount_ID() == acctAsset.getAccount_ID()) {
totalDebit = totalDebit.add(fa.getAmtAcctDr());
}
}
assertEquals(expectedCost, totalDebit.setScale(2, RoundingMode.HALF_EVEN), "Un-expected product asset account posted amount");
} finally {
rollback();
if (product != null && product.get_ID() > 0)
product.deleteEx(true);
if (tax != null && tax.get_ID() > 0)
tax.deleteEx(true);
if (category != null && category.get_ID() > 0)
category.deleteEx(true);
}
}
} }