Enhance MID_DocFactory, MID_CalloutMovement, and MID_CalloutPPO with new locator logic; update inventory handling in MID_MInventory and MID_MMovement; introduce MID_CalloutInventory and Doc_PSPPO for improved document processing.

This commit is contained in:
faisolavolut 2025-07-07 11:31:56 +07:00
parent 81684c9942
commit 64abb64200
16 changed files with 195 additions and 14 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="balinusa.midsuit.Doc">
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="balinusa.midsuit.doc">
<implementation class="balinusa.midsuit.factory.MID_DocFactory"/>
<property name="service.ranking" type="Integer" value="1"/>
<property name="gaap" type="String" value="*"/>

View File

@ -0,0 +1,37 @@
package balinusa.midsuit.callout;
import java.math.BigDecimal;
import java.util.Properties;
import org.adempiere.base.IColumnCallout;
import org.compiere.model.CalloutEngine;
import org.compiere.model.GridField;
import org.compiere.model.GridTab;
import org.compiere.model.X_M_InventoryLine;
import org.compiere.util.DB;
import balinusa.midsuit.model.MID_PPO;
public class MID_CalloutInventory extends CalloutEngine implements IColumnCallout {
@Override
public String start(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) {
if (mField.getColumnName().equals("PS_PPO_ID"))
return setWarehouseByPPO(ctx, WindowNo, mTab, mField, value, oldValue);
return null;
}
public String setWarehouseByPPO(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) {
if (value == null) {
return "";
}
MID_PPO pspo = new MID_PPO(ctx, (int) value, null);
if(pspo.get_ID() <= 0) {
return "";
}
int warehouseId = pspo.getM_Warehouse_ID();
mTab.setValue("M_Warehouse_ID", warehouseId);
return "";
}
}

View File

@ -6,6 +6,8 @@ import org.adempiere.base.IColumnCallout;
import org.compiere.model.CalloutEngine;
import org.compiere.model.GridField;
import org.compiere.model.GridTab;
import org.compiere.model.MLocator;
import org.compiere.model.Query;
public class MID_CalloutMovement extends CalloutEngine implements IColumnCallout{
@ -15,6 +17,27 @@ public class MID_CalloutMovement extends CalloutEngine implements IColumnCallout
if(mField.getColumnName().equals("M_Warehouse_ID"))
setMovement(ctx, WindowNo, mTab, mField, value, oldValue);
else if(mField.getColumnName().equals("M_WarehouseTo_ID"))
setLocatorTo(ctx, WindowNo, mTab, mField, value, oldValue);
return null;
}
public String setLocatorTo(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) {
if(value==null)
mTab.setValue("M_LocatorTo_ID", null);
else if((Integer) mTab.getValue("M_WarehouseTo_ID")>0){
int M_Warehouse_ID = (Integer) mTab.getValue("M_WarehouseTo_ID");
// search locator M_LocatorType name is POS and IsDefault='Y' in M_Locator and M_Warehouse_ID
int M_Locator_ID = new Query(ctx, MLocator.Table_Name, "M_Warehouse_ID=? AND EXISTS (SELECT 1 FROM M_LocatorType lt WHERE lt.M_LocatorType_ID = M_Locator.M_LocatorType_ID AND lt.Name='POS')", null)
.setParameters(new Object[] { M_Warehouse_ID })
.setOnlyActiveRecords(true)
.firstId();
if(M_Locator_ID > 0) {
mTab.setValue("M_LocatorTo_ID", M_Locator_ID);
} else {
mTab.setValue("M_LocatorTo_ID", null);
}
}
return null;
}

View File

@ -6,7 +6,10 @@ import org.adempiere.base.IColumnCallout;
import org.compiere.model.CalloutEngine;
import org.compiere.model.GridField;
import org.compiere.model.GridTab;
import org.compiere.model.MLocator;
import org.compiere.model.MPriceList;
import org.compiere.model.MProduct;
import org.compiere.model.Query;
import balinusa.midsuit.model.X_ps_ppo;
@ -17,9 +20,38 @@ public class MID_CalloutPPO extends CalloutEngine implements IColumnCallout{
if(mField.getColumnName().equals(X_ps_ppo.COLUMNNAME_M_Product_ID)){
return product(ctx, WindowNo, mTab, mField, value, oldValue);
}
if(mField.getColumnName().equals(X_ps_ppo.COLUMNNAME_C_DocTypeTarget_ID)) {
// set C_DocType_ID same with C_DocTypeTarget_ID
if (value != null) {
mTab.setValue(X_ps_ppo.COLUMNNAME_C_DocType_ID, value);
} else {
mTab.setValue(X_ps_ppo.COLUMNNAME_C_DocType_ID, 0);
}
return "";
}
if(mField.getColumnName().equals(X_ps_ppo.COLUMNNAME_M_Warehouse_ID)) {
setLocator(ctx, WindowNo, mTab, mField, value, oldValue);
return "";
}
return null;
}
// set M_Locator_ID from Warehouse Locator Default checked
private String setLocator(Properties ctx, int windowNo, GridTab mTab, GridField mField, Object value, Object oldValue) {
if (value == null) return "";
int M_Warehouse_ID = (int) value;
String sql = "SELECT M_Locator_ID FROM M_Locator WHERE IsDefault='Y' AND M_Warehouse_ID=?";
int M_Locator_ID = new Query(ctx, MLocator.Table_Name, "IsDefault='Y' AND M_Warehouse_ID=?", null)
.setParameters(new Object[] { M_Warehouse_ID })
.setOnlyActiveRecords(true)
.firstId();
if (M_Locator_ID > 0) {
mTab.setValue("M_Locator_ID", M_Locator_ID);
} else {
mTab.setValue("M_Locator_ID", null);
}
return "";
}
// set C_DocType_ID same with C_DocTypeTarget_ID
private String product(Properties ctx, int windowNo, GridTab mTab, GridField mField, Object value, Object oldValue) {
if (value==null) return "";

View File

@ -0,0 +1,35 @@
package balinusa.midsuit.doc;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.util.ArrayList;
import org.compiere.acct.Doc;
import org.compiere.acct.Fact;
import org.compiere.model.MAcctSchema;
import balinusa.midsuit.model.MID_PPO;;
public class Doc_PSPPO extends Doc{
public Doc_PSPPO (MAcctSchema as, ResultSet rs, String trxName)
{
super (as, MID_PPO.class, rs, null, trxName);
}
@Override
protected String loadDocumentDetails() {
return null;
}
@Override
public BigDecimal getBalance() {
return BigDecimal.ZERO;
}
@Override
public ArrayList<Fact> createFacts(MAcctSchema as) {
ArrayList<Fact> facts = new ArrayList<Fact>();
return facts;
}
}

View File

@ -7,6 +7,7 @@ import org.adempiere.base.IColumnCallout;
import org.adempiere.base.IColumnCalloutFactory;
import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine;
import org.compiere.model.MInventory;
import org.compiere.model.MInventoryLine;
import org.compiere.model.MInventoryLineMA;
import org.compiere.model.MMovementLineMA;
@ -20,6 +21,7 @@ import balinusa.midsuit.callout.MID_CalloutAnalysisQC;
import balinusa.midsuit.callout.MID_CalloutCeisaUpload;
import balinusa.midsuit.callout.MID_CalloutInOut;
import balinusa.midsuit.callout.MID_CalloutInOutLine;
import balinusa.midsuit.callout.MID_CalloutInventory;
import balinusa.midsuit.callout.MID_CalloutInventoryLine;
import balinusa.midsuit.callout.MID_CalloutInventoryLineMA;
import balinusa.midsuit.callout.MID_CalloutIsReturnCeisa;
@ -70,6 +72,8 @@ public class MID_CalloutFactory implements IColumnCalloutFactory{
list.add(new MID_CalloutInOutLine());
if(tableName.equals(MInventoryLine.Table_Name))
list.add(new MID_CalloutInventoryLine());
if(tableName.equals(MInventory.Table_Name))
list.add(new MID_CalloutInventory());
if(tableName.equals(MMovementLineMA.Table_Name))
list.add(new MID_CalloutMovementLineMA());
if(tableName.equals(MInventoryLineMA.Table_Name))

View File

@ -31,6 +31,7 @@ import balinusa.midsuit.model.MID_PPO;
public class MID_DocFactory implements IDocFactory{
protected transient CLogger log = CLogger.getCLogger (getClass());
private final static CLogger s_log = CLogger.getCLogger(MID_DocFactory.class);
@Override
@ -63,6 +64,7 @@ public class MID_DocFactory implements IDocFactory{
public Doc getDocument(MAcctSchema as, int AD_Table_ID, ResultSet rs, String trxName) {
String tableName = MTable.getTableName(Env.getCtx(), AD_Table_ID);
log.info("getDocument - TableName=" + tableName + ", AD_Table_ID=" + AD_Table_ID );
// if(tableName.equals(MID_MRequisitionTrx.Table_Name))
// return new MID_DocMidRequsiition(as,rs,trxName);
if(tableName.equals(MID_PPO.Table_Name))

View File

@ -30,7 +30,7 @@ public interface I_ps_ppo
{
/** TableName=ps_ppo */
public static final String Table_Name = "ps_ppo";
public static final String Table_Name = "PS_PPO";
/** AD_Table_ID=30013 */
public static final int Table_ID = 1000001;

View File

@ -30,7 +30,7 @@ public interface I_ps_ppoline
{
/** TableName=ps_ppoline */
public static final String Table_Name = "ps_ppoline";
public static final String Table_Name = "PS_PPOLine";
/** AD_Table_ID=30103 */
public static final int Table_ID = 1000012;
@ -122,6 +122,8 @@ public interface I_ps_ppoline
/** Column name M_Inventory_Issue_ID */
public static final String COLUMNNAME_M_Inventory_Issue_ID = "M_Inventory_Issue_ID";
public static final String COLUMNNAME_M_Locator_ID = "M_Locator_ID";
/** Set Inventory Issue */
public void setM_Inventory_Issue_ID (int M_Inventory_Issue_ID);

View File

@ -492,6 +492,8 @@ public class MID_MInventory extends MInventory {
inventoryLine.setAD_Org_ID(getAD_Org_ID());
inventoryLine.setM_Inventory_ID(getM_Inventory_ID());
inventoryLine.setM_Product_ID(ppoLine.getM_Product_ID());
// set Locator
inventoryLine.setM_Locator_ID(ppoLine.getM_Locator_ID());
// QtyEntered
inventoryLine.setC_Charge_ID(1000000);
BigDecimal qty = BigDecimal.valueOf(ppoLine.get_ValueAsInt("QtyUsed"));

View File

@ -1,9 +1,13 @@
package balinusa.midsuit.model;
import java.sql.ResultSet;
import java.util.List;
import java.util.Properties;
import org.compiere.model.MInventoryLine;
import org.compiere.model.MMovement;
import org.compiere.model.Query;
import org.compiere.process.DocAction;
import org.compiere.util.DB;
public class MID_MMovement extends MMovement{
@ -57,4 +61,37 @@ public class MID_MMovement extends MMovement{
return super.beforeSave(newRecord);
}
@Override
protected boolean afterSave(boolean newRecord, boolean success) {
if(success && !newRecord) {
int M_Inventory_ID = get_ValueAsInt("M_Inventory_ID");
int M_LocatorTo_ID = get_ValueAsInt("M_LocatorTo_ID");
if(M_Inventory_ID > 0) {
MID_MInventory inv = new MID_MInventory(getCtx(), M_Inventory_ID, get_TrxName());
if(inv.get_ID() > 0 && M_LocatorTo_ID > 0) {
List<MInventoryLine> lines = new Query(getCtx(), MInventoryLine.Table_Name, "M_InventoryLine.m_inventory_id =?", get_TrxName())
.addJoinClause(" JOIN M_Inventory i ON i.M_Inventory_ID=M_InventoryLine.M_Inventory_ID ")
.setOnlyActiveRecords(true)
.setParameters(new Object[] { M_Inventory_ID })
.list();
for(MInventoryLine line : lines) {
// create movement line for inventory line
if(line.get_ID() > 0 && line.getM_Product_ID() > 0 && line.getMovementQty().signum() != 0) {
MID_MMovementLine moveLine = new MID_MMovementLine(getCtx(), 0, get_TrxName());
moveLine.setM_Movement_ID(getM_Movement_ID());
moveLine.setM_Product_ID(line.getM_Product_ID());
moveLine.setMovementQty(line.getMovementQty());
moveLine.setM_Locator_ID(line.getM_Locator_ID());
moveLine.setM_LocatorTo_ID(M_LocatorTo_ID);
moveLine.saveEx();
}
}
}
}
}
return super.afterSave(newRecord, success);
}
}

View File

@ -377,7 +377,7 @@ public class MID_MOrder extends MOrder implements DocOptions{
if(newRecord) {
// check same org warehouse and ad_org
MWarehouse warehouse = MWarehouse.get(getCtx(), getM_Warehouse_ID());
if (warehouse.getAD_Org_ID() != getAD_Org_ID()) {
if (warehouse.getAD_Org_ID() > 0 && warehouse.getAD_Org_ID() != getAD_Org_ID()) {
setAD_Org_ID(warehouse.getAD_Org_ID());
}
}

View File

@ -97,10 +97,10 @@ public class MID_PPO extends X_ps_ppo implements DocAction, DocOptions{
.count();
if(countReceipt<=0 && countIssue<=0) {
if(countDisposal<=0 && countWaste<=0)
throw new AdempiereException("Pastikan ada Issue/Receipt yang diproses !!!");
}
// if(countReceipt<=0 && countIssue<=0) {
// if(countDisposal<=0 && countWaste<=0)
// throw new AdempiereException("Pastikan ada Issue/Receipt yang diproses !!!");
// }
return DocAction.STATUS_InProgress;
@ -126,11 +126,13 @@ public class MID_PPO extends X_ps_ppo implements DocAction, DocOptions{
.setOnlyActiveRecords(true)
.setParameters(new Object[] { getps_ppo_ID(),DocAction.STATUS_Completed })
.list();
DB.executeUpdateEx(" UPDATE PS_PPOLine SET QtyUsed=0 WHERE PS_PPO_ID =? ", new Object[] { getps_ppo_ID() }, get_TrxName() );
// DB.executeUpdateEx(" UPDATE PS_PPOLine SET QtyUsed=0 WHERE PS_PPO_ID =? ", new Object[] { getps_ppo_ID() }, get_TrxName() );
for(MInventoryLine line : lines) {
int PS_PPOLine_ID = line.get_ValueAsInt("ps_ppoline_ID");
if(PS_PPOLine_ID >0) {
log.info("Update Existing PS_PPOLine ID="+PS_PPOLine_ID+" for Product ID="+line.getM_Product_ID()+" Qty="+line.getQtyInternalUse());
MID_PPOLine ppoLine = new MID_PPOLine(getCtx(), line.get_ValueAsInt("ps_ppoline_ID"), get_TrxName());
log.info("Qty Used Before="+ppoLine.getQtyUsed());
ppoLine.setQtyUsed(ppoLine.getQtyUsed().add((BigDecimal) line.get_Value("QtyEntered")));
ppoLine.saveEx();
}else {

View File

@ -19,7 +19,4 @@ public class MID_PPOLine extends X_ps_ppoline {
super(ctx, rs, trxName);
// TODO Auto-generated constructor stub
}
}

View File

@ -127,6 +127,13 @@ public class X_ps_ppoline extends PO implements I_ps_ppoline, I_Persistent
set_Value (COLUMNNAME_M_Inventory_Issue_ID, Integer.valueOf(M_Inventory_Issue_ID));
}
public int getM_Locator_ID() {
Integer ii = (Integer)get_Value(COLUMNNAME_M_Locator_ID);
if (ii == null)
return 0;
return ii.intValue();
}
/** Get Inventory Issue.
@return Inventory Issue */
public int getM_Inventory_Issue_ID ()

View File

@ -50,6 +50,7 @@ public class MID_InventoryLineCreate extends SvrProcess{
invL.setAD_Org_ID(inv.getAD_Org_ID());
invL.setM_Inventory_ID(inv.getM_Inventory_ID());
invL.setM_Product_ID(line.getM_Product_ID());
invL.setM_Locator_ID(line.getM_Locator_ID());
if(line.isEndProduct())
invL.setQtyInternalUse(line.getQtyUsed().multiply(new BigDecimal(-1)));
else