IDEMPIERE-5433 Better invoice consolidation rules (#1504)
With acknowledgements to Carlos Ruiz for writing the test case.
This commit is contained in:
parent
56fe006d29
commit
84dc2b3f31
|
@ -91,6 +91,8 @@ public class InvoiceGenerate extends SvrProcess
|
||||||
private BigDecimal p_MinimumAmtInvSched = null;
|
private BigDecimal p_MinimumAmtInvSched = null;
|
||||||
/** Per Invoice Savepoint */
|
/** Per Invoice Savepoint */
|
||||||
private Savepoint m_savepoint = null;
|
private Savepoint m_savepoint = null;
|
||||||
|
/** BPartner on the last order processed */
|
||||||
|
private int m_bpartnerID = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare - e.g., get Parameters.
|
* 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 ")
|
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("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";
|
// sql += " FOR UPDATE";
|
||||||
|
|
||||||
|
@ -228,10 +230,13 @@ public class InvoiceGenerate extends SvrProcess
|
||||||
StringBuilder msgsup = new StringBuilder(Msg.getMsg(getCtx(), "Processing")).append(" ").append(order.getDocumentInfo());
|
StringBuilder msgsup = new StringBuilder(Msg.getMsg(getCtx(), "Processing")).append(" ").append(order.getDocumentInfo());
|
||||||
statusUpdate(msgsup.toString());
|
statusUpdate(msgsup.toString());
|
||||||
|
|
||||||
// New Invoice Location
|
// New BPartner, or new Invoice Location, or new Invoice Contact
|
||||||
if (!p_ConsolidateDocument
|
if (!p_ConsolidateDocument
|
||||||
|
|| (m_bpartnerID != 0
|
||||||
|
&& m_bpartnerID != order.getC_BPartner_ID())
|
||||||
|| (m_invoice != null
|
|| (m_invoice != null
|
||||||
&& m_invoice.getC_BPartner_Location_ID() != order.getBill_Location_ID()) )
|
&& (m_invoice.getC_BPartner_Location_ID() != order.getBill_Location_ID() ||
|
||||||
|
m_invoice.getAD_User_ID() != order.getBill_User_ID()) ) )
|
||||||
completeInvoice();
|
completeInvoice();
|
||||||
boolean completeOrder = MOrder.INVOICERULE_AfterOrderDelivered.equals(order.getInvoiceRule());
|
boolean completeOrder = MOrder.INVOICERULE_AfterOrderDelivered.equals(order.getInvoiceRule());
|
||||||
|
|
||||||
|
@ -350,6 +355,7 @@ public class InvoiceGenerate extends SvrProcess
|
||||||
m_line += 1000;
|
m_line += 1000;
|
||||||
}
|
}
|
||||||
} // complete Order
|
} // complete Order
|
||||||
|
m_bpartnerID = order.getC_BPartner_ID();
|
||||||
} // for all orders
|
} // for all orders
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -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 {
|
public enum C_Charge {
|
||||||
BANK(100),
|
BANK(100),
|
||||||
COMMISSIONS(101),
|
COMMISSIONS(101),
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.compiere.model.MRMA;
|
||||||
import org.compiere.model.MRMALine;
|
import org.compiere.model.MRMALine;
|
||||||
import org.compiere.model.PO;
|
import org.compiere.model.PO;
|
||||||
import org.compiere.model.SystemIDs;
|
import org.compiere.model.SystemIDs;
|
||||||
|
import org.compiere.model.X_C_BP_Relation;
|
||||||
import org.compiere.process.DocAction;
|
import org.compiere.process.DocAction;
|
||||||
import org.compiere.process.ProcessInfo;
|
import org.compiere.process.ProcessInfo;
|
||||||
import org.compiere.process.ServerProcessCtl;
|
import org.compiere.process.ServerProcessCtl;
|
||||||
|
@ -361,4 +362,108 @@ public class InvoiceCustomerTest extends AbstractTestCase {
|
||||||
rmaLine.load(getTrxName());
|
rmaLine.load(getTrxName());
|
||||||
assertEquals(1, rmaLine.getQtyInvoiced().intValue());
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue