IDEMPIERE-4623 Cash POS Sales Order is leaving wrong BP balance (#504)
This commit is contained in:
parent
09d7fea9e1
commit
11dc7a391f
|
@ -2076,7 +2076,11 @@ public class MInvoice extends X_C_Invoice implements DocAction
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
|
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
|
||||||
+ ") Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
+ ") Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
||||||
}
|
}
|
||||||
bp.setTotalOpenBalance(newBalance);
|
// the payment just created already updated the open balance
|
||||||
|
if ( ! (PAYMENTRULE_Cash.equals(getPaymentRule()) && !fromPOS ) )
|
||||||
|
{
|
||||||
|
bp.setTotalOpenBalance(newBalance);
|
||||||
|
}
|
||||||
bp.setSOCreditStatus();
|
bp.setSOCreditStatus();
|
||||||
if (!bp.save(get_TrxName()))
|
if (!bp.save(get_TrxName()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,13 +30,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.compiere.model.MAllocationHdr;
|
||||||
import org.compiere.model.MBPartner;
|
import org.compiere.model.MBPartner;
|
||||||
import org.compiere.model.MInOut;
|
import org.compiere.model.MInOut;
|
||||||
import org.compiere.model.MInOutLine;
|
import org.compiere.model.MInOutLine;
|
||||||
import org.compiere.model.MInvoice;
|
import org.compiere.model.MInvoice;
|
||||||
import org.compiere.model.MOrder;
|
import org.compiere.model.MOrder;
|
||||||
import org.compiere.model.MOrderLine;
|
import org.compiere.model.MOrderLine;
|
||||||
|
import org.compiere.model.MPayment;
|
||||||
import org.compiere.model.MProduct;
|
import org.compiere.model.MProduct;
|
||||||
import org.compiere.process.DocAction;
|
import org.compiere.process.DocAction;
|
||||||
import org.compiere.process.ProcessInfo;
|
import org.compiere.process.ProcessInfo;
|
||||||
|
@ -54,6 +57,10 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
public SalesOrderTest() {
|
public SalesOrderTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final static int BP_JOE_BLOCK = 118;
|
||||||
|
private static final int PRODUCT_OAK_TREE = 123;
|
||||||
|
private static final int PRODUCT_AZALEA = 128;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
/**
|
/**
|
||||||
* https://idempiere.atlassian.net/browse/IDEMPIERE-235
|
* https://idempiere.atlassian.net/browse/IDEMPIERE-235
|
||||||
|
@ -62,7 +69,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
//first test - invalid with completeorder and multiple datepromised
|
//first test - invalid with completeorder and multiple datepromised
|
||||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
//Joe Block
|
//Joe Block
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
@ -74,7 +81,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
MOrderLine line1 = new MOrderLine(order);
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
//Azalea Bush
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||||
line1.setQty(new BigDecimal("1"));
|
line1.setQty(new BigDecimal("1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
@ -82,7 +89,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
MOrderLine line2 = new MOrderLine(order);
|
MOrderLine line2 = new MOrderLine(order);
|
||||||
line2.setLine(20);
|
line2.setLine(20);
|
||||||
//Oak Tree
|
//Oak Tree
|
||||||
line2.setProduct(MProduct.get(Env.getCtx(), 123));
|
line2.setProduct(MProduct.get(Env.getCtx(), PRODUCT_OAK_TREE));
|
||||||
line2.setQty(new BigDecimal("1"));
|
line2.setQty(new BigDecimal("1"));
|
||||||
line2.setDatePromised(TimeUtil.addDays(today, 1));
|
line2.setDatePromised(TimeUtil.addDays(today, 1));
|
||||||
line2.saveEx();
|
line2.saveEx();
|
||||||
|
@ -97,7 +104,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
//second test - ok with completeorder and 1 datepromised
|
//second test - ok with completeorder and 1 datepromised
|
||||||
order = new MOrder(Env.getCtx(), 0, getTrxName());
|
order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
//Joe Block
|
//Joe Block
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
@ -108,7 +115,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
line1 = new MOrderLine(order);
|
line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
//Azalea Bush
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||||
line1.setQty(new BigDecimal("1"));
|
line1.setQty(new BigDecimal("1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
@ -116,7 +123,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
line2 = new MOrderLine(order);
|
line2 = new MOrderLine(order);
|
||||||
line2.setLine(20);
|
line2.setLine(20);
|
||||||
//Oak Tree
|
//Oak Tree
|
||||||
line2.setProduct(MProduct.get(Env.getCtx(), 123));
|
line2.setProduct(MProduct.get(Env.getCtx(), PRODUCT_OAK_TREE));
|
||||||
line2.setQty(new BigDecimal("1"));
|
line2.setQty(new BigDecimal("1"));
|
||||||
line2.setDatePromised(today);
|
line2.setDatePromised(today);
|
||||||
line2.saveEx();
|
line2.saveEx();
|
||||||
|
@ -131,7 +138,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
//test 3 - ok with !completeorder and multiple datepromised
|
//test 3 - ok with !completeorder and multiple datepromised
|
||||||
order = new MOrder(Env.getCtx(), 0, getTrxName());
|
order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
//Joe Block
|
//Joe Block
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_Availability);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_Availability);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
@ -142,7 +149,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
line1 = new MOrderLine(order);
|
line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
//Azalea Bush
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||||
line1.setQty(new BigDecimal("1"));
|
line1.setQty(new BigDecimal("1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
@ -150,7 +157,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
line2 = new MOrderLine(order);
|
line2 = new MOrderLine(order);
|
||||||
line2.setLine(20);
|
line2.setLine(20);
|
||||||
//Oak Tree
|
//Oak Tree
|
||||||
line2.setProduct(MProduct.get(Env.getCtx(), 123));
|
line2.setProduct(MProduct.get(Env.getCtx(), PRODUCT_OAK_TREE));
|
||||||
line2.setQty(new BigDecimal("1"));
|
line2.setQty(new BigDecimal("1"));
|
||||||
line2.setDatePromised(TimeUtil.addDays(today, 1));
|
line2.setDatePromised(TimeUtil.addDays(today, 1));
|
||||||
line2.saveEx();
|
line2.saveEx();
|
||||||
|
@ -167,7 +174,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
public void testQtyReservedForOverAndNegativeShipment() {
|
public void testQtyReservedForOverAndNegativeShipment() {
|
||||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
//Joe Block
|
//Joe Block
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
@ -180,7 +187,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
MOrderLine line1 = new MOrderLine(order);
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
//Azalea Bush
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||||
line1.setQty(new BigDecimal("1"));
|
line1.setQty(new BigDecimal("1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
@ -235,7 +242,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
public void testQtyReservedForNegativeOrderAndShipment() {
|
public void testQtyReservedForNegativeOrderAndShipment() {
|
||||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
//Joe Block
|
//Joe Block
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
@ -248,7 +255,7 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
MOrderLine line1 = new MOrderLine(order);
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
//Azalea Bush
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_AZALEA));
|
||||||
line1.setQty(new BigDecimal("-1"));
|
line1.setQty(new BigDecimal("-1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
@ -281,31 +288,37 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPOSOrder() {
|
public void testOnCreditPOSOrder() {
|
||||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
Properties ctx = Env.getCtx();
|
||||||
//Joe Block
|
String trxName = getTrxName();
|
||||||
order.setBPartner(MBPartner.get(Env.getCtx(), 118));
|
|
||||||
|
// Get the OpenBalance of Joe Block
|
||||||
|
MBPartner bpartner = new MBPartner(ctx, BP_JOE_BLOCK, trxName);
|
||||||
|
BigDecimal initialBalance = bpartner.getTotalOpenBalance();
|
||||||
|
|
||||||
|
MOrder order = new MOrder(ctx, 0, trxName);
|
||||||
|
order.setBPartner(MBPartner.get(ctx, BP_JOE_BLOCK));
|
||||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_POS);
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_POS);
|
||||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
order.setDocAction(DocAction.ACTION_Complete);
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
order.setPaymentRule(MOrder.PAYMENTRULE_OnCredit); // this is the default, just making it explicit
|
||||||
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
order.setDatePromised(today);
|
order.setDatePromised(today);
|
||||||
order.saveEx();
|
order.saveEx();
|
||||||
|
|
||||||
MOrderLine line1 = new MOrderLine(order);
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
line1.setLine(10);
|
line1.setLine(10);
|
||||||
//Azalea Bush
|
line1.setProduct(MProduct.get(ctx, PRODUCT_AZALEA));
|
||||||
line1.setProduct(MProduct.get(Env.getCtx(), 128));
|
|
||||||
line1.setQty(new BigDecimal("1"));
|
line1.setQty(new BigDecimal("1"));
|
||||||
line1.setDatePromised(today);
|
line1.setDatePromised(today);
|
||||||
line1.saveEx();
|
line1.saveEx();
|
||||||
|
|
||||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||||
assertFalse(info.isError(), info.getSummary());
|
assertFalse(info.isError(), info.getSummary());
|
||||||
order.load(getTrxName());
|
order.load(trxName);
|
||||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||||
line1.load(getTrxName());
|
line1.load(trxName);
|
||||||
assertEquals(0, line1.getQtyReserved().intValue());
|
assertEquals(0, line1.getQtyReserved().intValue());
|
||||||
assertEquals(1, line1.getQtyDelivered().intValue());
|
assertEquals(1, line1.getQtyDelivered().intValue());
|
||||||
assertEquals(1, line1.getQtyInvoiced().intValue());
|
assertEquals(1, line1.getQtyInvoiced().intValue());
|
||||||
|
@ -317,5 +330,71 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
MInvoice[] invoices = order.getInvoices();
|
MInvoice[] invoices = order.getInvoices();
|
||||||
assertEquals(1, invoices.length);
|
assertEquals(1, invoices.length);
|
||||||
assertEquals(DocAction.STATUS_Completed, invoices[0].getDocStatus());
|
assertEquals(DocAction.STATUS_Completed, invoices[0].getDocStatus());
|
||||||
|
|
||||||
|
bpartner.load(trxName);
|
||||||
|
BigDecimal actualBalance = bpartner.getTotalOpenBalance();
|
||||||
|
// on credit increases the debt
|
||||||
|
assertTrue(actualBalance.compareTo(initialBalance.add(order.getGrandTotal())) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCashPOSOrder() {
|
||||||
|
Properties ctx = Env.getCtx();
|
||||||
|
String trxName = getTrxName();
|
||||||
|
|
||||||
|
// Get the OpenBalance of Joe Block
|
||||||
|
MBPartner bpartner = new MBPartner(ctx, BP_JOE_BLOCK, trxName);
|
||||||
|
BigDecimal initialBalance = bpartner.getTotalOpenBalance();
|
||||||
|
|
||||||
|
MOrder order = new MOrder(ctx, 0, trxName);
|
||||||
|
order.setBPartner(MBPartner.get(ctx, BP_JOE_BLOCK));
|
||||||
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_POS);
|
||||||
|
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||||
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
order.setPaymentRule(MOrder.PAYMENTRULE_Cash);
|
||||||
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
|
order.setDatePromised(today);
|
||||||
|
order.saveEx();
|
||||||
|
|
||||||
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
|
line1.setLine(10);
|
||||||
|
line1.setProduct(MProduct.get(ctx, PRODUCT_AZALEA));
|
||||||
|
line1.setQty(new BigDecimal("1"));
|
||||||
|
line1.setDatePromised(today);
|
||||||
|
line1.saveEx();
|
||||||
|
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
order.load(trxName);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||||
|
line1.load(trxName);
|
||||||
|
assertEquals(0, line1.getQtyReserved().intValue());
|
||||||
|
assertEquals(1, line1.getQtyDelivered().intValue());
|
||||||
|
assertEquals(1, line1.getQtyInvoiced().intValue());
|
||||||
|
|
||||||
|
MInOut[] shipments = order.getShipments();
|
||||||
|
assertEquals(1, shipments.length);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, shipments[0].getDocStatus());
|
||||||
|
|
||||||
|
MInvoice[] invoices = order.getInvoices();
|
||||||
|
assertEquals(1, invoices.length);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, invoices[0].getDocStatus());
|
||||||
|
assertEquals(true, invoices[0].isPaid(), "Invoice is not paid");
|
||||||
|
|
||||||
|
MAllocationHdr[] allocs = MAllocationHdr.getOfInvoice(ctx, invoices[0].getC_Invoice_ID(), trxName);
|
||||||
|
assertEquals(1, allocs.length);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, allocs[0].getDocStatus());
|
||||||
|
|
||||||
|
int paymentId = allocs[0].getLines(false)[0].getC_Payment_ID();
|
||||||
|
MPayment payment = new MPayment(ctx, paymentId, trxName);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, payment.getDocStatus());
|
||||||
|
assertEquals(true, payment.isAllocated(), "Payment is not allocated");
|
||||||
|
|
||||||
|
bpartner.load(trxName);
|
||||||
|
BigDecimal actualBalance = bpartner.getTotalOpenBalance();
|
||||||
|
// cash creates payment immediately, so debt is not increased
|
||||||
|
assertTrue(actualBalance.compareTo(initialBalance) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue