IDEMPIERE-4654 Sales Order After Receipt Delivery Rule is not working (#536)
* IDEMPIERE-4654 Sales Order After Receipt Delivery Rule is not working create shipment if it is fully paid and stock is available use currencyconvertpayment - rename after receipt to after payment - added unit test for invoice payment Co-authored-by: Carlos Ruiz <carg67@gmail.com>
This commit is contained in:
parent
245b471d06
commit
f5e9cd9336
|
@ -0,0 +1,10 @@
|
|||
SET SQLBLANKLINES ON
|
||||
SET DEFINE OFF
|
||||
|
||||
-- Jan 26, 2021, 3:58:13 PM MYT
|
||||
UPDATE AD_Ref_List SET Name='After Payment', Description='After full payment has been received for the order',Updated=TO_DATE('2021-01-26 15:58:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=217
|
||||
;
|
||||
|
||||
SELECT register_migration_script('202101260800_IDEMPIERE-4654.sql') FROM dual
|
||||
;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
-- Jan 26, 2021, 3:58:13 PM MYT
|
||||
UPDATE AD_Ref_List SET Name='After Payment', Description='After full payment has been received for the order',Updated=TO_TIMESTAMP('2021-01-26 15:58:13','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=217
|
||||
;
|
||||
|
||||
SELECT register_migration_script('202101260800_IDEMPIERE-4654.sql') FROM dual
|
||||
;
|
||||
|
|
@ -220,6 +220,13 @@ public class InOutGenerate extends SvrProcess
|
|||
MOrder order = new MOrder (getCtx(), rs, get_TrxName());
|
||||
statusUpdate(Msg.getMsg(getCtx(), "Processing") + " " + order.getDocumentInfo());
|
||||
|
||||
if (MOrder.DELIVERYRULE_AfterReceipt.equals(order.getDeliveryRule()))
|
||||
{
|
||||
BigDecimal payment = order.getPaymentAmt();
|
||||
if (payment == null || payment.compareTo(order.getGrandTotal()) < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// New Header different Shipper, Shipment Location
|
||||
if (!p_ConsolidateDocument
|
||||
|| (m_shipment != null
|
||||
|
@ -337,7 +344,7 @@ public class InOutGenerate extends SvrProcess
|
|||
createLine (order, line, toDeliver, storages, false);
|
||||
}
|
||||
// Availability
|
||||
else if (MOrder.DELIVERYRULE_Availability.equals(order.getDeliveryRule())
|
||||
else if ((MOrder.DELIVERYRULE_Availability.equals(order.getDeliveryRule()) || MOrder.DELIVERYRULE_AfterReceipt.equals(order.getDeliveryRule()))
|
||||
&& (onHand.signum() > 0
|
||||
|| toDeliver.signum() < 0))
|
||||
{
|
||||
|
|
|
@ -19,7 +19,9 @@ package org.compiere.model;
|
|||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
@ -31,6 +33,7 @@ import org.adempiere.base.Core;
|
|||
import org.adempiere.exceptions.AdempiereException;
|
||||
import org.adempiere.exceptions.BPartnerNoBillToAddressException;
|
||||
import org.adempiere.exceptions.BPartnerNoShipToAddressException;
|
||||
import org.adempiere.exceptions.DBException;
|
||||
import org.adempiere.exceptions.FillMandatoryException;
|
||||
import org.adempiere.model.ITaxProvider;
|
||||
import org.adempiere.process.SalesOrderRateInquiryProcess;
|
||||
|
@ -3000,4 +3003,61 @@ public class MOrder extends X_C_Order implements DocAction
|
|||
return getC_DocType_ID() > 0 ? getC_DocType_ID() : getC_DocTypeTarget_ID();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return payment amount for order (prepayment + invoice payment)
|
||||
*/
|
||||
public BigDecimal getPaymentAmt()
|
||||
{
|
||||
BigDecimal orderPaid = null;
|
||||
String sql = "SELECT SUM(currencyconvertpayment(p.c_payment_id, o.c_currency_id, p.PayAmt+p.DiscountAmt+p.WriteOffAmt, null) "
|
||||
+ " - paymentallocated(p.c_payment_id, o.c_currency_id) "
|
||||
+ " * (CASE WHEN p.IsReceipt='Y' THEN 1 ELSE -1 END)) "
|
||||
+ "FROM C_Payment p "
|
||||
+ "INNER JOIN C_Order o ON (p.C_Order_ID=o.C_Order_ID) "
|
||||
+ "WHERE p.C_Order_ID=? AND p.AD_Client_ID=? "
|
||||
+ "AND p.IsActive='Y' AND p.DocStatus IN ('CO','CL') ";
|
||||
|
||||
try (PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName());)
|
||||
{
|
||||
pstmt.setInt(1, getC_Order_ID());
|
||||
pstmt.setInt(2, getAD_Client_ID());
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
if (rs.next())
|
||||
{
|
||||
orderPaid = rs.getBigDecimal(1);
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new DBException(e, sql);
|
||||
}
|
||||
|
||||
BigDecimal invoicePaid = null;
|
||||
sql = "SELECT SUM(invoicepaid(i.c_invoice_id, o.c_currency_id, 1)) "
|
||||
+ "FROM C_Invoice i "
|
||||
+ "INNER JOIN C_Order o ON (i.C_Order_ID=o.C_Order_ID) "
|
||||
+ "WHERE i.C_Order_ID=? AND i.AD_Client_ID=? "
|
||||
+ "AND i.IsActive='Y' AND i.DocStatus IN ('CO','CL') ";
|
||||
|
||||
try (PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName());)
|
||||
{
|
||||
pstmt.setInt(1, getC_Order_ID());
|
||||
pstmt.setInt(2, getAD_Client_ID());
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
if (rs.next())
|
||||
{
|
||||
invoicePaid = rs.getBigDecimal(1);
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new DBException(e, sql);
|
||||
}
|
||||
|
||||
BigDecimal retValue = orderPaid != null ? orderPaid : BigDecimal.ZERO;
|
||||
if (invoicePaid != null)
|
||||
retValue = retValue.add(invoicePaid);
|
||||
return retValue;
|
||||
}
|
||||
} // MOrder
|
||||
|
|
|
@ -23,6 +23,7 @@ public class ServerProcessCtl implements Runnable {
|
|||
/** Process Info */
|
||||
ProcessInfo m_pi;
|
||||
private Trx m_trx;
|
||||
private boolean managedTrxForJavaProcess = true;
|
||||
|
||||
/**************************************************************************
|
||||
* Constructor
|
||||
|
@ -324,7 +325,7 @@ public class ServerProcessCtl implements Runnable {
|
|||
if (m_pi.getClassName().toLowerCase().startsWith(MRule.SCRIPT_PREFIX)) {
|
||||
return ProcessUtil.startScriptProcess(Env.getCtx(), m_pi, m_trx);
|
||||
} else {
|
||||
return ProcessUtil.startJavaProcess(Env.getCtx(), m_pi, m_trx);
|
||||
return ProcessUtil.startJavaProcess(Env.getCtx(), m_pi, m_trx, managedTrxForJavaProcess);
|
||||
}
|
||||
} // startProcess
|
||||
|
||||
|
@ -341,4 +342,21 @@ public class ServerProcessCtl implements Runnable {
|
|||
return ProcessUtil.startDatabaseProcedure(m_pi, ProcedureName, m_trx);
|
||||
} // startDBProcess
|
||||
|
||||
/**
|
||||
* set whether java process call will commit/rollback trx (default is true)
|
||||
* @param managedTrx
|
||||
*/
|
||||
public void setManagedTrxForJavaProcess(boolean managedTrx)
|
||||
{
|
||||
this.managedTrxForJavaProcess = managedTrx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if java process call will commit/rollback trx
|
||||
*/
|
||||
public boolean isManagedTrxForJavaProcess()
|
||||
{
|
||||
return managedTrxForJavaProcess;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
**********************************************************************/
|
||||
package org.idempiere.test.model;
|
||||
|
||||
import static org.compiere.model.SystemIDs.PROCESS_M_INOUT_GENERATE_MANUAL;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -39,10 +40,15 @@ import org.compiere.model.MInOutLine;
|
|||
import org.compiere.model.MInvoice;
|
||||
import org.compiere.model.MOrder;
|
||||
import org.compiere.model.MOrderLine;
|
||||
import org.compiere.model.MPInstance;
|
||||
import org.compiere.model.MPInstancePara;
|
||||
import org.compiere.model.MPayment;
|
||||
import org.compiere.model.MProduct;
|
||||
import org.compiere.model.SystemIDs;
|
||||
import org.compiere.process.DocAction;
|
||||
import org.compiere.process.ProcessInfo;
|
||||
import org.compiere.process.ServerProcessCtl;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.util.TimeUtil;
|
||||
import org.compiere.wf.MWorkflow;
|
||||
|
@ -397,4 +403,244 @@ public class SalesOrderTest extends AbstractTestCase {
|
|||
assertTrue(actualBalance.compareTo(initialBalance) == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateShipmentDeliveryRule() {
|
||||
//test1 with CompleteOrder
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
//Joe Block
|
||||
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||
order.setDateOrdered(today);
|
||||
order.setDatePromised(today);
|
||||
order.saveEx();
|
||||
|
||||
MOrderLine line1 = new MOrderLine(order);
|
||||
line1.setLine(10);
|
||||
//Azalea Bush
|
||||
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||
line1.setQty(new BigDecimal("1"));
|
||||
line1.setDatePromised(today);
|
||||
line1.saveEx();
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError());
|
||||
order.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
line1.load(getTrxName());
|
||||
assertEquals(1, line1.getQtyReserved().intValue());
|
||||
|
||||
int AD_Process_ID = PROCESS_M_INOUT_GENERATE_MANUAL;
|
||||
MPInstance instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
|
||||
instance.saveEx();
|
||||
|
||||
String insert = "INSERT INTO T_SELECTION(AD_PINSTANCE_ID, T_SELECTION_ID) Values (?, ?)";
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order.getC_Order_ID()}, null);
|
||||
|
||||
//call process
|
||||
ProcessInfo pi = new ProcessInfo ("InOutGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
MPInstancePara ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "CO");
|
||||
ip.saveEx();
|
||||
// Add Parameter - M_Warehouse_ID=x
|
||||
ip = new MPInstancePara(instance, 30);
|
||||
ip.setParameter("M_Warehouse_ID", getM_Warehouse_ID());
|
||||
ip.saveEx();
|
||||
|
||||
ServerProcessCtl processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
|
||||
line1.load(getTrxName());
|
||||
assertEquals(0, line1.getQtyReserved().intValue());
|
||||
assertEquals(1, line1.getQtyDelivered().intValue());
|
||||
order.getLines();
|
||||
rollback();
|
||||
|
||||
//test2 with AfterReceipt
|
||||
MOrder order1 = MOrder.copyFrom(order, today, order.getC_DocType_ID(), true, false, false, getTrxName());
|
||||
order1.setDeliveryRule(MOrder.DELIVERYRULE_AfterReceipt);
|
||||
order1.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(order1, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError());
|
||||
order1.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, order1.getDocStatus());
|
||||
line1 = order1.getLines()[0];
|
||||
line1.load(getTrxName());
|
||||
assertEquals(1, line1.getQtyReserved().intValue());
|
||||
|
||||
instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
|
||||
instance.saveEx();
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order1.getC_Order_ID()}, null);
|
||||
|
||||
//call process without payment
|
||||
pi = new ProcessInfo ("InOutGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "CO");
|
||||
ip.saveEx();
|
||||
// Add Parameter - M_Warehouse_ID=x
|
||||
ip = new MPInstancePara(instance, 30);
|
||||
ip.setParameter("M_Warehouse_ID", getM_Warehouse_ID());
|
||||
ip.saveEx();
|
||||
|
||||
processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
|
||||
line1.load(getTrxName());
|
||||
assertEquals(1, line1.getQtyReserved().intValue());
|
||||
assertEquals(0, line1.getQtyDelivered().intValue());
|
||||
|
||||
//create payment
|
||||
MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName());
|
||||
payment.setC_DocType_ID(true);
|
||||
int C_BankAccount_ID = DB.getSQLValueEx(getTrxName(), "select c_bankaccount_id from c_bankaccount where ad_client_id=? and isdefault='Y'", getAD_Client_ID());
|
||||
payment.setC_BankAccount_ID(C_BankAccount_ID);
|
||||
payment.setC_BPartner_ID(order1.getC_BPartner_ID());
|
||||
payment.setC_Order_ID(order1.getC_Order_ID());
|
||||
payment.setTenderType(MPayment.TENDERTYPE_DirectDeposit);
|
||||
payment.setPayAmt(order1.getGrandTotal());
|
||||
payment.setC_Currency_ID(order1.getC_Currency_ID());
|
||||
payment.saveEx();
|
||||
info = MWorkflow.runDocumentActionWorkflow(payment, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError());
|
||||
payment.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, payment.getDocStatus());
|
||||
|
||||
//call process with payment
|
||||
instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
|
||||
instance.saveEx();
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order1.getC_Order_ID()}, null);
|
||||
pi = new ProcessInfo ("InOutGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "CO");
|
||||
ip.saveEx();
|
||||
// Add Parameter - M_Warehouse_ID=x
|
||||
ip = new MPInstancePara(instance, 30);
|
||||
ip.setParameter("M_Warehouse_ID", getM_Warehouse_ID());
|
||||
ip.saveEx();
|
||||
|
||||
processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
|
||||
line1.load(getTrxName());
|
||||
assertEquals(0, line1.getQtyReserved().intValue());
|
||||
assertEquals(1, line1.getQtyDelivered().intValue());
|
||||
|
||||
//test3 with AfterReceipt
|
||||
MOrder order2 = MOrder.copyFrom(order, today, order.getC_DocType_ID(), true, false, false, getTrxName());
|
||||
order2.setDeliveryRule(MOrder.DELIVERYRULE_AfterReceipt);
|
||||
order2.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(order2, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError());
|
||||
order2.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, order2.getDocStatus());
|
||||
line1 = order2.getLines()[0];
|
||||
line1.load(getTrxName());
|
||||
assertEquals(1, line1.getQtyReserved().intValue());
|
||||
|
||||
//create invoice
|
||||
instance = new MPInstance(Env.getCtx(), SystemIDs.PROCESS_C_INVOICE_GENERATE, 0);
|
||||
instance.saveEx();
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order2.getC_Order_ID()}, null);
|
||||
pi = new ProcessInfo ("InvoiceGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "CO");
|
||||
ip.saveEx();
|
||||
|
||||
processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
|
||||
line1.load(getTrxName());
|
||||
assertEquals(1, line1.getQtyReserved().intValue());
|
||||
assertEquals(1, line1.getQtyInvoiced().intValue());
|
||||
|
||||
//create payment
|
||||
payment = new MPayment(Env.getCtx(), 0, getTrxName());
|
||||
payment.setC_DocType_ID(true);
|
||||
payment.setC_BankAccount_ID(C_BankAccount_ID);
|
||||
payment.setC_BPartner_ID(order2.getC_BPartner_ID());
|
||||
payment.setC_Invoice_ID(DB.getSQLValueEx(getTrxName(), "SELECT C_Invoice_ID FROM C_Invoice WHERE C_Order_ID=?", order2.getC_Order_ID()));
|
||||
payment.setTenderType(MPayment.TENDERTYPE_DirectDeposit);
|
||||
payment.setPayAmt(order2.getGrandTotal());
|
||||
payment.setC_Currency_ID(order2.getC_Currency_ID());
|
||||
payment.saveEx();
|
||||
info = MWorkflow.runDocumentActionWorkflow(payment, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError());
|
||||
payment.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, payment.getDocStatus());
|
||||
|
||||
//call process with payment
|
||||
instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
|
||||
instance.saveEx();
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order2.getC_Order_ID()}, null);
|
||||
pi = new ProcessInfo ("InOutGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "CO");
|
||||
ip.saveEx();
|
||||
// Add Parameter - M_Warehouse_ID=x
|
||||
ip = new MPInstancePara(instance, 30);
|
||||
ip.setParameter("M_Warehouse_ID", getM_Warehouse_ID());
|
||||
ip.saveEx();
|
||||
|
||||
processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
|
||||
line1.load(getTrxName());
|
||||
assertEquals(0, line1.getQtyReserved().intValue());
|
||||
assertEquals(1, line1.getQtyDelivered().intValue());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue