Valorated packing slip list

Good morning,

I am managing a development, and we are working on an enhancement to be able to generate the SalesPackingSlip with the tax values also shown for each line. The way I am retrieving it right now is the following:

AmountMST taxAmount;
TaxValue  taxPct;
str       taxCodes;

container taxInfo = this.getSalesLineTaxInfoFromPackingSlip(
    custPackingSlipTrans.custPackingslipJour(),
    custPackingSlipTrans,
    salesLine);

taxAmount = conPeek(taxInfo, 1);
taxPct    = conPeek(taxInfo, 2);
taxCodes  = conPeek(taxInfo, 3);

if (!taxCodes)
{
    taxInfo = this.getSalesLineTaxInfo(salesLine);
    taxAmount = conPeek(taxInfo, 1);
    taxPct    = conPeek(taxInfo, 2);
}

_addingRecord.addCalculatedField('FRITaxAmount', taxAmount);
_addingRecord.addCalculatedField('FRITaxValue', taxPct);
_addingRecord.addCalculatedField('FRITaxCode', taxCodes);

//////////////////////////////////////////////////////////////////////////////////

private container getSalesLineTaxInfo(SalesLine _salesLine)
{
    AmountMST taxAmount = 0;
    TaxValue  taxPct = 0;

    if (!_salesLine.RecId)
    {
        return [taxAmount, taxPct];
    }

    TaxGroup     taxGroup     = _salesLine.TaxGroup;
    TaxItemGroup taxItemGroup = _salesLine.TaxItemGroup;
    CurrencyCode currencyCode = _salesLine.CurrencyCode;

    if (!taxGroup || !currencyCode)
    {
        SalesTable salesTable = SalesTable::find(_salesLine.SalesId);

        if (!taxGroup)
        {
            taxGroup = salesTable.TaxGroup;
        }

        if (!currencyCode)
        {
            currencyCode = salesTable.CurrencyCode;
        }
    }

    if (!taxItemGroup)
    {
        return [taxAmount, taxPct];
    }

    if (!taxGroup || !taxItemGroup || !currencyCode)
    {
        return [taxAmount, taxPct];
    }

    AmountCur baseAmountCur = _salesLine.LineAmount;
    if (!baseAmountCur)
    {
        return [taxAmount, taxPct];
    }

    TransDate transDate = systemDateGet();

    TaxAmountCur taxAmountCur = Tax::calcTaxAmount(
        taxGroup,
        taxItemGroup,
        transDate,
        currencyCode,
        baseAmountCur,
        TaxModuleType::Sales);

    taxAmount = abs(taxAmountCur);
    taxPct = round(abs(taxAmountCur) / abs(baseAmountCur) * 100, 2);

    return [taxAmount, taxPct];
}

private container getSalesLineTaxInfoFromPackingSlip(
    CustPackingSlipJour _custPackingSlipJour,
    CustPackingSlipTrans _custPackingSlipTrans,
    SalesLine _salesLine)
{
    AmountMST taxAmount = 0;
    TaxValue  taxPct = 0;
    str       taxCodes = '';

    if (!_custPackingSlipJour.RecId || !_custPackingSlipTrans.RecId || !_salesLine.RecId)
    {
        return [taxAmount, taxPct, taxCodes];
    }

    TaxSales taxSales = this.getCachedTaxSalesForPackingSlip(_custPackingSlipJour);
    if (!taxSales)
    {
        return [taxAmount, taxPct, taxCodes];
    }

    taxSales.showTaxesSourceSingleLine(tableNum(SalesLine), _salesLine.RecId, true);
    TmpTaxWorkTrans tmpTaxWorkTrans = taxSales.tmpTaxWorkTrans();

    AmountCur taxAmountCur = 0;
    AmountCur taxBaseAmountCur = 0;
    Set taxCodeSet = new Set(Types::String);

    while select tmpTaxWorkTrans
        where tmpTaxWorkTrans.SourceTableId == tableNum(SalesLine)
           && tmpTaxWorkTrans.SourceRecId == _salesLine.RecId
    {
        taxAmountCur += tmpTaxWorkTrans.TaxAmount;
        taxBaseAmountCur += tmpTaxWorkTrans.TaxBaseAmount;

        if (tmpTaxWorkTrans.TaxCode)
        {
            taxCodeSet.add(tmpTaxWorkTrans.TaxCode);
        }
    }

    taxAmount = abs(taxAmountCur);
    taxCodes = this.joinSet(taxCodeSet, ';');
    taxPct = taxBaseAmountCur ? round(abs(taxAmountCur) / abs(taxBaseAmountCur) * 100, 2) : 0;

    return [taxAmount, taxPct, taxCodes];
}

private TaxSales getCachedTaxSalesForPackingSlip(CustPackingSlipJour _custPackingSlipJour)
{
    Map cache = new Map(Types::String, Types::Class);
    str key = strFmt('%1|%2', _custPackingSlipJour.DataAreaId, _custPackingSlipJour.RecId);

    if (cache.exists(key))
    {
        return cache.lookup(key);
    }

    TaxSales taxSales = null;
    SalesParmTable salesParmTable = SalesParmTable::findSalesId(_custPackingSlipJour.SalesId, _custPackingSlipJour.ParmId);

    if (salesParmTable.RecId)
    {
        SalesParmUpdate salesParmUpdate = salesParmTable.salesParmUpdate();
        SalesTotals salesTotals = SalesTotals::construct(
            salesParmTable,
            salesParmUpdate.SpecQty,
            salesParmUpdate.SumBy,
            salesParmUpdate.ParmId,
            salesParmUpdate.SumSalesId,
            DocumentStatus::PackingSlip);

        salesTotals.calc();
        taxSales = salesTotals.tax();
    }

    cache.insert(key, taxSales);
    return taxSales;
}

private str joinSet(Set _set, str _separator)
{
    if (!_set)
    {
        return '';
    }

    SetEnumerator se = _set.getEnumerator();
    str result = '';

    while (se.moveNext())
    {
        str value = se.current();
        if (!value)
        {
            continue;
        }

        result = result ? strFmt('%1%2%3', result, _separator, value) : value;
    }

    return result;
}

I am having many issues with the DDP generation part, as they are taking too long to be generated. Do you have any tips to improve this development?

In the end, the idea is that for each line, the system calculates the TaxCode. With that TaxCode, it should retrieve the tax amount for each line, and it should also calculate the taxes applied to each line.

Hi Aarón,

Thank you for sharing the details.

Please note that the SalesPackingSlip report is not one of the scenarios explicitly covered by our DocTaxCalculator examples. The examples currently cover Sales invoice, Free text invoice, Project invoice, and similar invoice-related scenarios.

Still, the forum post below can be a useful reference point:

How to use DocTaxCalculator class to add tax amount per line to Project, Free text and Sales invoices

The DocTaxCalculator class contains the logic for calculating tax amounts per line, and it may give you ideas on how to improve or simplify your current implementation. You can compare your approach with the examples and test whether the same logic can be adapted for the packing slip scenario.

Please also keep in mind that calculating tax amounts per line can impact report execution performance, especially when the calculation is done for each line during DDSP generation. This is most likely why tax amounts are not shown per line in the standard SSRS report output by default.

So, our recommendation would be:

  1. Review the DocTaxCalculator examples.
  2. Try adapting the same approach for SalesPackingSlip .
  3. Test carefully with realistic data volumes.
  4. Pay special attention to caching and avoiding repeated tax recalculations for the same document or line.

At this point, we cannot confirm that DocTaxCalculator fully supports the SalesPackingSlip report out of the box, but it should be a good starting point for improving your current solution.