From 6b89176b2f395d73ccbe229aacc773872d1739f9 Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Tue, 22 May 2018 19:31:54 +0200 Subject: [PATCH] iIDEMPIERE-918 Allow to choose the reversal document for invoice / created a process that allows the user to create a credit memo instead of reversing --- .../oracle/201805221532_IDEMPIERE-918.sql | 51 ++++ .../postgresql/201805221532_IDEMPIERE-918.sql | 48 ++++ .../process/InvoiceCreateCreditMemo.java | 222 ++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 migration/i5.1/oracle/201805221532_IDEMPIERE-918.sql create mode 100644 migration/i5.1/postgresql/201805221532_IDEMPIERE-918.sql create mode 100644 org.adempiere.base.process/src/org/idempiere/process/InvoiceCreateCreditMemo.java diff --git a/migration/i5.1/oracle/201805221532_IDEMPIERE-918.sql b/migration/i5.1/oracle/201805221532_IDEMPIERE-918.sql new file mode 100644 index 0000000000..1bc6b1560f --- /dev/null +++ b/migration/i5.1/oracle/201805221532_IDEMPIERE-918.sql @@ -0,0 +1,51 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-918 +-- May 22, 2018 3:17:13 PM CEST +INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200100,0,0,'Y',TO_DATE('2018-05-22 15:17:13','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:17:13','YYYY-MM-DD HH24:MI:SS'),100,'Create Credit Memo','Creates a credit memo based on the invoice.','The invoice should be correct and completed.','N','InvoiceCreateCreditMemo','N','org.idempiere.process.InvoiceCreateCreditMemo','1','D',0,0,'N','N','Y','N','68540275-9c56-4e1b-99f5-d155eb62a12b') +; + +-- May 22, 2018 3:22:56 PM CEST +INSERT INTO AD_Val_Rule (AD_Val_Rule_ID,Name,Description,Type,Code,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Val_Rule_UU) VALUES (200118,'C_DocTypeTarget AR/AP Credit Memos','Target Document Type AR/AP Credit Memos','S','C_DocType.DocBaseType IN (''ARC'',''APC'') AND C_DocType.IsSOTrx=''@IsSOTrx@'' AND C_DocType.AD_Client_ID=@#AD_Client_ID@',0,0,'Y',TO_DATE('2018-05-22 15:22:56','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:22:56','YYYY-MM-DD HH24:MI:SS'),100,'D','b27e8ab7-8128-43b2-b94d-175c3f77e4cf') +; + +-- May 22, 2018 3:24:44 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,AD_Val_Rule_ID,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200228,0,0,'Y',TO_DATE('2018-05-22 15:24:44','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:24:44','YYYY-MM-DD HH24:MI:SS'),100,'Document Type','Document type or rules','The Document Type determines document sequence and processing rules',200100,10,19,'N',200118,10,'Y','C_DocType_ID','Y','D',196,'0022f86c-0629-4d70-84c3-cc6a506fdf7c','N') +; + +-- May 22, 2018 3:28:49 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200229,0,0,'Y',TO_DATE('2018-05-22 15:28:49','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:28:49','YYYY-MM-DD HH24:MI:SS'),100,'Date Invoiced','Date printed on Invoice','The Date Invoice indicates the date printed on the invoice.',200100,20,15,'N',10,'Y','@#Date@','DateInvoiced','Y','D',267,'0c954e16-967b-4b48-9075-8a134b72e2d2','N') +; + +-- May 22, 2018 3:29:12 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200230,0,0,'Y',TO_DATE('2018-05-22 15:29:12','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:29:12','YYYY-MM-DD HH24:MI:SS'),100,'Account Date','Accounting Date','The Accounting Date indicates the date to be used on the General Ledger account entries generated from this document. It is also used for any currency conversion.',200100,30,15,'N',10,'Y','@#Date@','DateAcct','Y','D',263,'4edbbf7b-c6d3-4b3d-84b7-1591c204b91d','N') +; + +-- May 22, 2018 3:30:49 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,AD_Reference_Value_ID,IsRange,AD_Val_Rule_ID,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200231,0,0,'Y',TO_DATE('2018-05-22 15:30:49','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 15:30:49','YYYY-MM-DD HH24:MI:SS'),100,'Document Action','The targeted status of the document','You find the current status in the Document Status field. The options are listed in a popup',200100,40,17,135,'N',219,0,'N','DocAction','Y','D',287,'ce0b15c4-5e79-4dfd-b11b-0992911df4b4','N') +; + +-- May 22, 2018 3:32:01 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,Action,AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo) VALUES (0,0,TO_DATE('2018-05-22 15:32:01','YYYY-MM-DD HH24:MI:SS'),100,'InvoiceCustomerCreateCreditMemo','Y',200096,'InvoiceCustomerCreateCreditMemo',TO_DATE('2018-05-22 15:32:01','YYYY-MM-DD HH24:MI:SS'),100,'N','ebf24687-2124-496b-89ee-5d75e05743a3','W',263,200100,'@DocStatus@=''CO'' | @DocStatus@=''CL''',10) +; + +-- May 22, 2018 3:32:35 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,Action,AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo) VALUES (0,0,TO_DATE('2018-05-22 15:32:34','YYYY-MM-DD HH24:MI:SS'),100,'InvoiceVendorCreateCreditMemo','Y',200097,'InvoiceVendorCreateCreditMemo',TO_DATE('2018-05-22 15:32:34','YYYY-MM-DD HH24:MI:SS'),100,'N','2e2c53e9-4e1e-4789-8caf-c772e601e107','W',290,200100,'@DocStatus@=''CO'' | @DocStatus@=''CL''',10) +; + +-- May 22, 2018 7:25:46 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Invoice has already allocations',0,0,'Y',TO_DATE('2018-05-22 19:25:46','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 19:25:46','YYYY-MM-DD HH24:MI:SS'),100,200471,'InvoiceHasAllocations','D','f0dc5362-437e-4fd9-bdc9-c8b472678765') +; + +-- May 22, 2018 7:26:13 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Cannot create a credit memo from a credit memo',0,0,'Y',TO_DATE('2018-05-22 19:26:13','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 19:26:13','YYYY-MM-DD HH24:MI:SS'),100,200472,'CannotCreateCreditMemoFromCreditMemo','D','36370a38-ec58-4e1f-8804-e869a17730ac') +; + +-- May 22, 2018 7:26:37 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Credit Memo already exists',0,0,'Y',TO_DATE('2018-05-22 19:26:37','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-05-22 19:26:37','YYYY-MM-DD HH24:MI:SS'),100,200473,'CreditMemoAlreadyExists','D','c67e63fc-4a41-45dc-b52c-317688b125d2') +; + +SELECT register_migration_script('201805221532_IDEMPIERE-918.sql') FROM dual +; + diff --git a/migration/i5.1/postgresql/201805221532_IDEMPIERE-918.sql b/migration/i5.1/postgresql/201805221532_IDEMPIERE-918.sql new file mode 100644 index 0000000000..e074f1617f --- /dev/null +++ b/migration/i5.1/postgresql/201805221532_IDEMPIERE-918.sql @@ -0,0 +1,48 @@ +-- IDEMPIERE-918 +-- May 22, 2018 3:17:13 PM CEST +INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200100,0,0,'Y',TO_TIMESTAMP('2018-05-22 15:17:13','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:17:13','YYYY-MM-DD HH24:MI:SS'),100,'Create Credit Memo','Creates a credit memo based on the invoice.','The invoice should be correct and completed.','N','InvoiceCreateCreditMemo','N','org.idempiere.process.InvoiceCreateCreditMemo','1','D',0,0,'N','N','Y','N','68540275-9c56-4e1b-99f5-d155eb62a12b') +; + +-- May 22, 2018 3:22:56 PM CEST +INSERT INTO AD_Val_Rule (AD_Val_Rule_ID,Name,Description,Type,Code,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Val_Rule_UU) VALUES (200118,'C_DocTypeTarget AR/AP Credit Memos','Target Document Type AR/AP Credit Memos','S','C_DocType.DocBaseType IN (''ARC'',''APC'') AND C_DocType.IsSOTrx=''@IsSOTrx@'' AND C_DocType.AD_Client_ID=@#AD_Client_ID@',0,0,'Y',TO_TIMESTAMP('2018-05-22 15:22:56','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:22:56','YYYY-MM-DD HH24:MI:SS'),100,'D','b27e8ab7-8128-43b2-b94d-175c3f77e4cf') +; + +-- May 22, 2018 3:24:44 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,AD_Val_Rule_ID,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200228,0,0,'Y',TO_TIMESTAMP('2018-05-22 15:24:44','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:24:44','YYYY-MM-DD HH24:MI:SS'),100,'Document Type','Document type or rules','The Document Type determines document sequence and processing rules',200100,10,19,'N',200118,10,'Y','C_DocType_ID','Y','D',196,'0022f86c-0629-4d70-84c3-cc6a506fdf7c','N') +; + +-- May 22, 2018 3:28:49 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200229,0,0,'Y',TO_TIMESTAMP('2018-05-22 15:28:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:28:49','YYYY-MM-DD HH24:MI:SS'),100,'Date Invoiced','Date printed on Invoice','The Date Invoice indicates the date printed on the invoice.',200100,20,15,'N',10,'Y','@#Date@','DateInvoiced','Y','D',267,'0c954e16-967b-4b48-9075-8a134b72e2d2','N') +; + +-- May 22, 2018 3:29:12 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200230,0,0,'Y',TO_TIMESTAMP('2018-05-22 15:29:12','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:29:12','YYYY-MM-DD HH24:MI:SS'),100,'Account Date','Accounting Date','The Accounting Date indicates the date to be used on the General Ledger account entries generated from this document. It is also used for any currency conversion.',200100,30,15,'N',10,'Y','@#Date@','DateAcct','Y','D',263,'4edbbf7b-c6d3-4b3d-84b7-1591c204b91d','N') +; + +-- May 22, 2018 3:30:49 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,AD_Reference_Value_ID,IsRange,AD_Val_Rule_ID,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200231,0,0,'Y',TO_TIMESTAMP('2018-05-22 15:30:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 15:30:49','YYYY-MM-DD HH24:MI:SS'),100,'Document Action','The targeted status of the document','You find the current status in the Document Status field. The options are listed in a popup',200100,40,17,135,'N',219,0,'N','DocAction','Y','D',287,'ce0b15c4-5e79-4dfd-b11b-0992911df4b4','N') +; + +-- May 22, 2018 3:32:01 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,"action",AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo) VALUES (0,0,TO_TIMESTAMP('2018-05-22 15:32:01','YYYY-MM-DD HH24:MI:SS'),100,'InvoiceCustomerCreateCreditMemo','Y',200096,'InvoiceCustomerCreateCreditMemo',TO_TIMESTAMP('2018-05-22 15:32:01','YYYY-MM-DD HH24:MI:SS'),100,'N','ebf24687-2124-496b-89ee-5d75e05743a3','W',263,200100,'@DocStatus@=''CO'' | @DocStatus@=''CL''',10) +; + +-- May 22, 2018 3:32:35 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,"action",AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo) VALUES (0,0,TO_TIMESTAMP('2018-05-22 15:32:34','YYYY-MM-DD HH24:MI:SS'),100,'InvoiceVendorCreateCreditMemo','Y',200097,'InvoiceVendorCreateCreditMemo',TO_TIMESTAMP('2018-05-22 15:32:34','YYYY-MM-DD HH24:MI:SS'),100,'N','2e2c53e9-4e1e-4789-8caf-c772e601e107','W',290,200100,'@DocStatus@=''CO'' | @DocStatus@=''CL''',10) +; + +-- May 22, 2018 7:25:46 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Invoice has already allocations',0,0,'Y',TO_TIMESTAMP('2018-05-22 19:25:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 19:25:46','YYYY-MM-DD HH24:MI:SS'),100,200471,'InvoiceHasAllocations','D','f0dc5362-437e-4fd9-bdc9-c8b472678765') +; + +-- May 22, 2018 7:26:13 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Cannot create a credit memo from a credit memo',0,0,'Y',TO_TIMESTAMP('2018-05-22 19:26:13','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 19:26:13','YYYY-MM-DD HH24:MI:SS'),100,200472,'CannotCreateCreditMemoFromCreditMemo','D','36370a38-ec58-4e1f-8804-e869a17730ac') +; + +-- May 22, 2018 7:26:37 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Credit Memo already exists',0,0,'Y',TO_TIMESTAMP('2018-05-22 19:26:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-05-22 19:26:37','YYYY-MM-DD HH24:MI:SS'),100,200473,'CreditMemoAlreadyExists','D','c67e63fc-4a41-45dc-b52c-317688b125d2') +; + +SELECT register_migration_script('201805221532_IDEMPIERE-918.sql') FROM dual +; + diff --git a/org.adempiere.base.process/src/org/idempiere/process/InvoiceCreateCreditMemo.java b/org.adempiere.base.process/src/org/idempiere/process/InvoiceCreateCreditMemo.java new file mode 100644 index 0000000000..6654076b90 --- /dev/null +++ b/org.adempiere.base.process/src/org/idempiere/process/InvoiceCreateCreditMemo.java @@ -0,0 +1,222 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - Carlos Ruiz * + **********************************************************************/ +package org.idempiere.process; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.logging.Level; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MAllocationHdr; +import org.compiere.model.MAllocationLine; +import org.compiere.model.MDocType; +import org.compiere.model.MInvoice; +import org.compiere.model.MInvoiceLine; +import org.compiere.model.MPeriod; +import org.compiere.process.DocAction; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.Msg; + +/** + * IDEMPIERE-918 Generate credit memo from invoice + * @author Carlos Ruiz - globalqss + */ +public class InvoiceCreateCreditMemo extends SvrProcess { + /* The document type for the credit memo */ + private int p_C_DocType_ID = 0; + /* Invoice Date */ + private Timestamp p_DateInvoiced = null; + /* Accounting Date */ + private Timestamp p_DateAcct = null; + /* Document Action */ + private String p_DocAction = null; + /* Create allocation between the invoice and the credit memo */ + private boolean p_IsCreateAllocation = false; + /* The invoice being credited */ + private MInvoice invoice = null; + + /** + * Prepare - e.g., get Parameters. + */ + protected void prepare() { + for (ProcessInfoParameter para : getParameter()) { + String name = para.getParameterName(); + switch (name) { + case "C_DocType_ID": + p_C_DocType_ID = para.getParameterAsInt(); + break; + case "DateInvoiced": + p_DateInvoiced = para.getParameterAsTimestamp(); + break; + case "DateAcct": + p_DateAcct = para.getParameterAsTimestamp(); + break; + case "DocAction": + p_DocAction = para.getParameterAsString(); + break; + case "IsCreateAllocation": + p_IsCreateAllocation = para.getParameterAsBoolean(); + break; + default: + log.log(Level.SEVERE, "Unknown Parameter: " + name); + } + } + invoice = new MInvoice(getCtx(), getRecord_ID(), get_TrxName()); + } // prepare + + /** + * Perform process. + * @return Message + * @throws Exception + */ + protected String doIt() throws Exception { + if (log.isLoggable(Level.INFO)) log.info("C_Invoice_ID" + invoice.getC_Invoice_ID() + ", C_DocType_ID=" + p_C_DocType_ID + ", DateInvoiced=" + p_DateInvoiced + + ", DateAcct=" + p_DateAcct + ", DocAction=" + p_DocAction); + + if (p_IsCreateAllocation) { + // validate - cannot create allocation if the invoice is already paid or partially paid + MAllocationHdr[] allocs = MAllocationHdr.getOfInvoice(getCtx(), invoice.getC_Invoice_ID(), get_TrxName()); + if (allocs.length > 0) { + throw new AdempiereException(Msg.getMsg(getCtx(), "InvoiceHasAllocations")); + } + } + // validate just for invoices, not for credit memos + if (invoice.isCreditMemo()) { + throw new AdempiereException(Msg.getMsg(getCtx(), "CannotCreateCreditMemoFromCreditMemo")); + } + // Validate if there is already another credit memo for this invoice (via POReference) + final String sql = "" + + "SELECT C_Invoice_ID " + + "FROM C_Invoice i " + + " JOIN C_DocType dt ON ( i.C_DocType_ID = dt.C_DocType_ID ) " + + "WHERE i.POReference = ? " + + " AND dt.DocBaseType IN ( ?, ? ) " + + " AND i.C_BPartner_ID = ? " + + " AND i.AD_Client_ID = ? " + + " AND i.AD_Org_ID = ?"; + int id = DB.getSQLValue(get_TrxName(), sql, + invoice.getDocumentNo(), + MDocType.DOCBASETYPE_APCreditMemo, MDocType.DOCBASETYPE_ARCreditMemo, + invoice.getC_BPartner_ID(), + invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); + if (id > 0) { + MInvoice actualCreditMemo = MInvoice.get(getCtx(), id); + MDocType dtc = MDocType.get(getCtx(), actualCreditMemo.getC_DocTypeTarget_ID()); + addLog(0, null, null, dtc.getName() + " " + actualCreditMemo.getDocumentNo(), MInvoice.Table_ID, actualCreditMemo.getC_Invoice_ID()); + throw new AdempiereException(Msg.getMsg(getCtx(), "CreditMemoAlreadyExists")); + } + + MInvoice creditMemo = credit(); + if (creditMemo != null) { + MDocType dtc = MDocType.get(getCtx(), creditMemo.getC_DocTypeTarget_ID()); + addLog(0, null, null, dtc.getName() + " " + creditMemo.getDocumentNo(), MInvoice.Table_ID, creditMemo.getC_Invoice_ID()); + } + + return "@OK@"; + } // doIt + + private MInvoice credit() { + Timestamp creditDate = p_DateAcct; + Timestamp creditDateInvoiced = p_DateInvoiced; + MPeriod.testPeriodOpen(getCtx(), creditDate, p_C_DocType_ID, invoice.getAD_Org_ID()); + + // Deep Copy + MInvoice creditMemo = null; + creditMemo = MInvoice.copyFrom(invoice, creditDateInvoiced, creditDate, p_C_DocType_ID, invoice.isSOTrx(), false, get_TrxName(), true); + if (creditMemo == null) { + throw new AdempiereException("Could not create Credit Memo"); + } + + // Reverse Line Qty + MInvoiceLine[] oLines = invoice.getLines(false); + MInvoiceLine[] rLines = creditMemo.getLines(true); + if (oLines.length != rLines.length) { + throw new AdempiereException("Credit Memo created with different number of lines than invoice"); + } + for (int i = 0; i < rLines.length; i++) { + MInvoiceLine rLine = rLines[i]; + MInvoiceLine oLine = oLines[i]; + rLine.setQtyEntered(oLine.getQtyEntered()); + rLine.setQtyInvoiced(oLine.getQtyInvoiced()); + rLine.setLineNetAmt(oLine.getLineNetAmt()); + rLine.setTaxAmt(oLine.getTaxAmt()); + rLine.setLineTotalAmt(oLine.getLineTotalAmt()); + rLine.setPriceActual(oLine.getPriceActual()); + rLine.setPriceList(oLine.getPriceList()); + rLine.setPriceLimit(oLine.getPriceLimit()); + rLine.setPriceEntered(oLine.getPriceEntered()); + rLine.setC_UOM_ID(oLine.getC_UOM_ID()); + if (!rLine.save(get_TrxName())) { + throw new AdempiereException("Could not create credit memo line"); + } + } + if (MInvoice.PAYMENTRULE_Cash.equals(creditMemo.getPaymentRule())) { + creditMemo.setPaymentRule(MInvoice.PAYMENTRULE_OnCredit); // avoid creation of automatic payment + } + creditMemo.setC_Order_ID(invoice.getC_Order_ID()); + StringBuilder msgadd = new StringBuilder("{->").append(invoice.getDocumentNo()).append(")"); + creditMemo.addDescription(msgadd.toString()); + creditMemo.setPOReference(invoice.getDocumentNo()); + creditMemo.saveEx(get_TrxName()); + // + if (p_DocAction != null) { + if (!creditMemo.processIt(p_DocAction)) { + throw new AdempiereException("ERROR processing credit memo " + p_DocAction + " -> " + creditMemo.getProcessMsg()); + } + if (p_IsCreateAllocation && DocAction.ACTION_Complete.equals(p_DocAction)) { + // Create Allocation + StringBuilder msgall = new StringBuilder().append(Msg.translate(getCtx(), "C_Invoice_ID")).append(": ").append(invoice.getDocumentNo()).append("/").append(creditMemo.getDocumentNo()); + MAllocationHdr alloc = new MAllocationHdr(getCtx(), false, creditDate, + invoice.getC_Currency_ID(), + msgall.toString(), + get_TrxName()); + alloc.setAD_Org_ID(invoice.getAD_Org_ID()); + alloc.saveEx(); + // Amount + BigDecimal gt = invoice.getGrandTotal(true); + if (!invoice.isSOTrx()) + gt = gt.negate(); + // Invoice Line + MAllocationLine aLine = new MAllocationLine (alloc, gt, Env.ZERO, Env.ZERO, Env.ZERO); + aLine.setC_Invoice_ID(invoice.getC_Invoice_ID()); + aLine.saveEx(); + // Credit Line + MAllocationLine cLine = new MAllocationLine (alloc, gt.negate(), Env.ZERO, Env.ZERO, Env.ZERO); + cLine.setC_Invoice_ID(creditMemo.getC_Invoice_ID()); + cLine.saveEx(); + if (!alloc.processIt(DocAction.ACTION_Complete)) + throw new AdempiereException("Failed when processing document - " + alloc.getProcessMsg()); + // end added + alloc.saveEx(); + } + } + + return creditMemo; + } + +} // InvoiceCreateCreditMemo