diff --git a/org.adempiere.base.process/src/org/compiere/process/InvoiceGenerate.java b/org.adempiere.base.process/src/org/compiere/process/InvoiceGenerate.java index c4f88d687b..b38855865c 100644 --- a/org.adempiere.base.process/src/org/compiere/process/InvoiceGenerate.java +++ b/org.adempiere.base.process/src/org/compiere/process/InvoiceGenerate.java @@ -91,6 +91,8 @@ public class InvoiceGenerate extends SvrProcess private BigDecimal p_MinimumAmtInvSched = null; /** Per Invoice Savepoint */ private Savepoint m_savepoint = null; + /** BPartner on the last order processed */ + private int m_bpartnerID = 0; /** * Prepare - e.g., get Parameters. @@ -177,7 +179,7 @@ public class InvoiceGenerate extends SvrProcess // sql.append(") AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType ") .append("WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR')) ") - .append("ORDER BY AD_Org_ID, M_Warehouse_ID, PriorityRule, C_BPartner_ID, Bill_Location_ID, C_Order_ID"); + .append("ORDER BY AD_Org_ID, M_Warehouse_ID, PriorityRule, C_BPartner_ID, Bill_Location_ID, Bill_User_ID, C_Order_ID"); } // sql += " FOR UPDATE"; @@ -228,10 +230,13 @@ public class InvoiceGenerate extends SvrProcess StringBuilder msgsup = new StringBuilder(Msg.getMsg(getCtx(), "Processing")).append(" ").append(order.getDocumentInfo()); statusUpdate(msgsup.toString()); - // New Invoice Location - if (!p_ConsolidateDocument - || (m_invoice != null - && m_invoice.getC_BPartner_Location_ID() != order.getBill_Location_ID()) ) + // New BPartner, or new Invoice Location, or new Invoice Contact + if (!p_ConsolidateDocument + || (m_bpartnerID != 0 + && m_bpartnerID != order.getC_BPartner_ID()) + || (m_invoice != null + && (m_invoice.getC_BPartner_Location_ID() != order.getBill_Location_ID() || + m_invoice.getAD_User_ID() != order.getBill_User_ID()) ) ) completeInvoice(); boolean completeOrder = MOrder.INVOICERULE_AfterOrderDelivered.equals(order.getInvoiceRule()); @@ -350,6 +355,7 @@ public class InvoiceGenerate extends SvrProcess m_line += 1000; } } // complete Order + m_bpartnerID = order.getC_BPartner_ID(); } // for all orders } catch (Exception e) diff --git a/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java b/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java index b9fbaa3826..98117fb4fd 100644 --- a/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java +++ b/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java @@ -107,6 +107,16 @@ public final class DictionaryIDs { } } + public enum C_BPartner_Location { + C_AND_W_STAMFORD(112); + + public final int id; + + private C_BPartner_Location(int id) { + this.id = id; + } + } + public enum C_Charge { BANK(100), COMMISSIONS(101), diff --git a/org.idempiere.test/src/org/idempiere/test/model/InvoiceCustomerTest.java b/org.idempiere.test/src/org/idempiere/test/model/InvoiceCustomerTest.java index 6ec5496669..d16345b4de 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/InvoiceCustomerTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/InvoiceCustomerTest.java @@ -49,6 +49,7 @@ import org.compiere.model.MRMA; import org.compiere.model.MRMALine; import org.compiere.model.PO; import org.compiere.model.SystemIDs; +import org.compiere.model.X_C_BP_Relation; import org.compiere.process.DocAction; import org.compiere.process.ProcessInfo; import org.compiere.process.ServerProcessCtl; @@ -361,4 +362,108 @@ public class InvoiceCustomerTest extends AbstractTestCase { rmaLine.load(getTrxName()); assertEquals(1, rmaLine.getQtyInvoiced().intValue()); } + + @Test + public void testGenerateInvoiceRelatedBP() { // IDEMPIERE-5433 + X_C_BP_Relation bpr = new X_C_BP_Relation(Env.getCtx(), 0, getTrxName()); + bpr.setName("C&W may pay invoices for Seed"); + bpr.setC_BPartner_ID(DictionaryIDs.C_BPartner.SEED_FARM.id); + bpr.setC_BPartnerRelation_ID(DictionaryIDs.C_BPartner.C_AND_W.id); + bpr.setC_BPartnerRelation_Location_ID(DictionaryIDs.C_BPartner_Location.C_AND_W_STAMFORD.id); + bpr.setIsBillTo(true); + bpr.setIsRemitTo(true); + bpr.saveEx(); + + MOrder order1 = new MOrder(Env.getCtx(), 0, getTrxName()); + order1.setBPartner(MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id)); + order1.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard); + order1.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder); + order1.setInvoiceRule(MOrder.INVOICERULE_Immediate); + order1.setDocStatus(DocAction.STATUS_Drafted); + order1.setDocAction(DocAction.ACTION_Complete); + order1.setBill_BPartner_ID(DictionaryIDs.C_BPartner.C_AND_W.id); + order1.setBill_Location_ID(DictionaryIDs.C_BPartner_Location.C_AND_W_STAMFORD.id); + Timestamp today = TimeUtil.getDay(System.currentTimeMillis()); + order1.setDateOrdered(today); + order1.setDatePromised(today); + order1.saveEx(); + + MOrderLine line1 = new MOrderLine(order1); + line1.setLine(10); + line1.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.SEEDER.id)); + line1.setQty(new BigDecimal("1")); + line1.setDatePromised(today); + line1.saveEx(); + + ProcessInfo info1 = MWorkflow.runDocumentActionWorkflow(order1, DocAction.ACTION_Complete); + assertFalse(info1.isError(), info1.getSummary()); + order1.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order1.getDocStatus()); + line1.load(getTrxName()); + assertEquals(1, line1.getQtyReserved().intValue()); + assertEquals(0, line1.getQtyInvoiced().intValue()); + + MOrder order2 = new MOrder(Env.getCtx(), 0, getTrxName()); + order2.setBPartner(MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.SEED_FARM.id)); + order2.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard); + order2.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder); + order2.setInvoiceRule(MOrder.INVOICERULE_Immediate); + order2.setDocStatus(DocAction.STATUS_Drafted); + order2.setDocAction(DocAction.ACTION_Complete); + order2.setBill_BPartner_ID(DictionaryIDs.C_BPartner.C_AND_W.id); + order2.setBill_Location_ID(DictionaryIDs.C_BPartner_Location.C_AND_W_STAMFORD.id); + order2.setDateOrdered(today); + order2.setDatePromised(today); + order2.saveEx(); + + MOrderLine line2 = new MOrderLine(order2); + line2.setLine(10); + line2.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.WEEDER.id)); + line2.setQty(new BigDecimal("1")); + line2.setDatePromised(today); + line2.saveEx(); + + ProcessInfo info2 = MWorkflow.runDocumentActionWorkflow(order2, DocAction.ACTION_Complete); + assertFalse(info2.isError(), info2.getSummary()); + order2.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order2.getDocStatus()); + line2.load(getTrxName()); + assertEquals(1, line2.getQtyReserved().intValue()); + assertEquals(0, line2.getQtyInvoiced().intValue()); + + int AD_Process_ID = SystemIDs.PROCESS_C_INVOICE_GENERATE; + MPInstance instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0); + instance.saveEx(); + + //call process + ProcessInfo pi = new ProcessInfo ("InvoiceGenerate", AD_Process_ID); + pi.setAD_PInstance_ID (instance.getAD_PInstance_ID()); + + // Add Parameter - Selection=Y + MPInstancePara ip = new MPInstancePara(instance, 10); + ip.setParameter("DateInvoiced",today); + ip.saveEx(); + // Org + ip = new MPInstancePara(instance, 20); + ip.setParameter("AD_Org_ID", DictionaryIDs.AD_Org.HQ.id); + ip.saveEx(); + //Add Document action parameter + ip = new MPInstancePara(instance, 50); + ip.setParameter("DocAction", MOrder.DOCACTION_Prepare); + ip.saveEx(); + // Consolidate + ip = new MPInstancePara(instance, 60); + ip.setParameter("ConsolidateDocument", true); + ip.saveEx(); + + ServerProcessCtl processCtl = new ServerProcessCtl(pi, getTrx()); + processCtl.setManagedTrxForJavaProcess(false); + processCtl.run(); + + assertFalse(pi.isError(), pi.getSummary()); + // It must create two invoices because they are for different ship BP + // even if they have the same Bill BP and Location + assertEquals(pi.getSummary(), "Created = 2"); + } + }