在发货和发票中覆盖运费金额

开箱即用 Acumatica 允许创建和维护系统中的运输条款列表。装运条款用于定义运输,包装和处理成本,具体取决于装运量。

在此示例中,我将展示如何根据销售订单金额计算货件的运费金额,这将允许用户为每个销售订单创建多个货件,并自动将相同的运输条款应用于所有货件。

FreightCalculator

FreightCalculator 类负责计算运费和运费条款。出于此示例的目的,我们只关注 GetFreightTerms 方法:

public class FreightCalculator
{
    ...

    protected virtual ShipTermsDetail GetFreightTerms(string shipTermsID, decimal? lineTotal)
    {
        return PXSelect<ShipTermsDetail,
            Where<ShipTermsDetail.shipTermsID, Equal<Required<SOOrder.shipTermsID>>,
            And<ShipTermsDetail.breakAmount, LessEqual<Required<SOOrder.lineTotal>>>>,
            OrderBy<Desc<ShipTermsDetail.breakAmount>>>.Select(graph, shipTermsID, lineTotal);
    }

    ...
}

无论是销售订单出货量的屏幕采用 FreightCalculator 类来计算分别基于销售订单的出货的量运费金额:

销售订单

public class SOOrderEntry : PXGraph<SOOrderEntry, SOOrder>, PXImportAttribute.IPXPrepareItems
{
    ...

    public virtual FreightCalculator CreateFreightCalculator()
    {
        return new FreightCalculator(this);
    }

    ...

    protected virtual void SOOrder_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
    {
        ...

        PXResultset<SOLine> res = Transactions.Select();
        FreightCalculator fc = CreateFreightCalculator();
        fc.CalcFreight<SOOrder, SOOrder.curyFreightCost, SOOrder.curyFreightAmt>(sender, (SOOrder)e.Row, res.Count);

        ...
    }

    ...
}

出货量

public class SOShipmentEntry : PXGraph<SOShipmentEntry, SOShipment>
{
    ...

    protected virtual FreightCalculator CreateFreightCalculator()
    {
        return new FreightCalculator(this);
    }

    ...

    protected virtual void SOShipment_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
    {
        ...

        PXResultset<SOShipLine> res = Transactions.Select();
        ...
        FreightCalculator fc = CreateFreightCalculator();
        fc.CalcFreight<SOShipment, SOShipment.curyFreightCost, SOShipment.curyFreightAmt>(sender, (SOShipment)e.Row, res.Count);

        ...
    }

    ...
}

覆盖运费金额

要自定义 Acumatica 如何在“ 货件” 屏幕上计算运费金额,我将声明从 FreightCalculator 继承的 FreightCalculatorCst 类并覆盖 GetFreightTerms 方法:

public class FreightCalculatorCst : FreightCalculator
{
    public FreightCalculatorCst(PXGraph graph)
        : base(graph)
    {
    }

    protected override ShipTermsDetail GetFreightTerms(string shipTermsID, decimal? lineTotal)
    {
        if (graph is SOShipmentEntry)
        {
            var shipmentEntry = graph as SOShipmentEntry;
            int orderCount = 0;
            decimal? lineTotalTemp = null;

            foreach (PXResult<SOOrderShipment, SOOrder, CurrencyInfo, SOAddress, SOContact, SOOrderType> orderRec in 
                shipmentEntry.OrderList.SelectWindowed(0, 2))
            {
                orderCount++;
                SOOrder order = (SOOrder)orderRec;
                if (orderCount == 1)
                    lineTotalTemp = order.LineTotal;
                else
                    break;
            }

            if (orderCount == 1)
            {
                lineTotal = lineTotalTemp;
            }
        }

        return base.GetFreightTerms(shipTermsID, lineTotal);
    }
}

之后,我将实施 SOShipmentEntry BLC 的扩展,并覆盖 CreateFreightCalculator 方法,在发货屏幕上用我的自定义 FreightCalculatorCst 类替换 FreightCalculator

public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
    [PXOverride]
    public FreightCalculator CreateFreightCalculator()
    {
        return new FreightCalculatorCst(Base);
    }
}

了解上面示例中的 FreightCalculatorCst 类的实现

在重写的 GetFreightTerms 方法中,我将使用销售订单中的金额而不是装运金额来调用基础 GetFreightTerms 方法并接收装运条款:

foreach (PXResult<SOOrderShipment, SOOrder, CurrencyInfo, SOAddress, SOContact, SOOrderType> orderRec in 
    shipmentEntry.OrderList.SelectWindowed(0, 2))
{
    orderCount++;
    SOOrder order = (SOOrder)orderRec;
    if (orderCount == 1)
        lineTotalTemp = order.LineTotal;
    else
        break;
}

if (orderCount == 1)
{
    lineTotal = lineTotalTemp;
}

显然,只能使用销售订单金额来计算货件的运费,这只能满足 1 个订单。如果一批货物满足多个订单,我们必须遵循基本产品行为并根据装运量计算运费。为了检查装运完成的订单数量,我在 OrderList 数据视图中使用了 SelectWindowed 方法,并请求当前装运完成的前 2 个订单。我本来可以请求装运完成的所有订单,但这需要更多的时间来执行并返回多个记录所需的数据,以验证是否可以使用销售订单金额而不是装运金额来计算运费。