This is about the following report – Procurement and Sourcing / Reports / Status / Accrued purchases.
In AX2012 (companing with AX2009) we’ve made a performance improvement of the report by changing it’s datasource. But if you use discounts the report might show you a wrong value. Below you will find a way to resolve it.
Scenario. In case you apply a discount to a purchase order and then post a packing slip, the amount of the packign slip’s Purchase, accrual is the amount before discount (for example, 1000), but the report will show you the amounts after discount (for example, 900). So there’s a discrepancy between the report and the real posting.
Below is an illustration of the code that will resolve the issue, but the report may work a bit slower. The new code lines are marked in yellow.
\Classes\VendAccruedPurchasesDP_NA\processReport
/// <summary>
/// Processes the SQL Server Reporting Services report business logic.
/// </summary>
/// <remarks>
/// This method provides the ability to write the report business logic. This method will be called by
/// SQL Server Reporting Services (SSRS) at run time. The method should compute data and populate the
/// data tables that will be returned to SSRS.
/// </remarks>
[SysEntryPointAttribute(false)]
publicvoid
processReport()
{
VendInvoiceTrans vendInvoiceTrans, vendInvoiceTransNotExists;
VendTable vendTable;
InventTransOrigin inventTransOrigin;
InventTrans inventTrans;
VendInvoicePackingSlipQuantityMatch qtyMatched, qtyMatchedNotExists;
VendAccruedPurchasesPartialInvoicedQty partialInvoiced, partialInvoicedBeforeCutOff;
this.getParametersFromContract();
this.processReportQuery();
if (physicalOnly)
{
this.buildPhysicalOnlyVendAccruedPurchases(true);
this.buildPhysicalOnlyVendAccruedPurchases(false);
}
else
{
this.buildVendAccruedPurchases();
}
// Now that all rows exist for the report, do set-based
// updates to fill in the remaining columns
// Remove the product receipt records that don’t have invoices and are after the cut-off date
delete_from vendAccruedPurchasesTmp_NA
where vendAccruedPurchasesTmp_NA.DatePhysical > cutOffDate
notexistsjoin qtyMatched where
qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine;
// Remove the records that have product receipts and invoices that are after the cut-off date and don’t have
// invoices that are prior to the cut-off date
delete_from vendAccruedPurchasesTmp_NA
where vendAccruedPurchasesTmp_NA.DatePhysical > cutOffDate
existsjoin qtyMatched where
qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
join vendInvoiceTrans where
vendInvoiceTrans.SourceDocumentLine == qtyMatched.InvoiceSourceDocumentLIne
&& vendInvoiceTrans.InvoiceDate > cutOffDate
notexistsjoin qtyMatchedNotExists where
qtyMatchedNotExists.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
join SourceDocumentLine, InvoiceDate from vendInvoiceTransNotExists where
vendInvoiceTransNotExists.SourceDocumentLine == qtyMatchedNotExists.InvoiceSourceDocumentLIne
&& vendInvoiceTransNotExists.InvoiceDate <= cutOffDate;
// Summation of partial invoiced quantity cannot be done in the
// original insert_recordset as it would change the cardinality of
// the rows in the report. Similarly, it can’t be done in a simple
// update_recordset because update_recordset does not support summation..
// Instead, do an insert_recordset with a sum into a staging table,
// and then update out of that staging table.
// At this point partialInvoiced may still contain quantities for the fully invoiced records.
// We will delete them from vendAccruedPurchasesTmp_NA in the next statement.
insert_recordset partialInvoiced (PackingSlipSourceDocumentLine, PartiallyInvoicedQuantity)
select PackingSlipSourceDocumentLine from vendAccruedPurchasesTmp_NA
groupby vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
where vendAccruedPurchasesTmp_NA.DatePhysical <= cutOffDate
joinsum(Quantity) from qtyMatched where
qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
existsjoin vendInvoiceTrans where
vendInvoiceTrans.SourceDocumentLine == qtyMatched.InvoiceSourceDocumentLIne
&& vendInvoiceTrans.InvoiceDate <= cutOffDate;
// Remove those records that have already been fully invoiced (Qty = InvoicedQty)
delete_from vendAccruedPurchasesTmp_NA
existsjoin partialInvoiced where
partialInvoiced.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
&& vendAccruedPurchasesTmp_NA.Qty == partialInvoiced.PartiallyInvoicedQuantity;
// Grab and sum up records that are invoiced prior to the cut-off date, but were received after the cut-off date
insert_recordset partialInvoicedBeforeCutOff (PackingSlipSourceDocumentLine, PartiallyInvoicedQuantity)
select PackingSlipSourceDocumentLine from vendAccruedPurchasesTmp_NA
groupby vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
where vendAccruedPurchasesTmp_NA.DatePhysical > cutOffDate
joinsum(Quantity) from qtyMatched where
qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
existsjoin vendInvoiceTrans where
vendInvoiceTrans.SourceDocumentLine == qtyMatched.InvoiceSourceDocumentLIne
&& vendInvoiceTrans.InvoiceDate <= cutOffDate;
// Date the invoice was posted
update_recordset vendAccruedPurchasesTmp_NA setting
DateFinancial = vendInvoiceTrans.InvoiceDate,
CostAmountPosted = (vendInvoiceTrans.LineAmountMST / vendInvoiceTrans.Qty) * vendAccruedPurchasesTmp_NA.Qty
join qtyMatched
where qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
joinmaxOf(InvoiceDate), LineAmountMST, Qty from vendInvoiceTrans
where vendInvoiceTrans.SourceDocumentLine == qtyMatched.InvoiceSourceDocumentLine;
// Vendor name
update_recordSet vendAccruedPurchasesTmp_NA setting
VendName = dirPartyTable.Name
join dirPartyTable
existsjoin vendTable where
vendTable.AccountNum == vendAccruedPurchasesTmp_NA.InvoiceAccount &&
vendTable.Party == dirPartyTable.RecId;
// Cost amount posted (has to be calculated *after* Qty is calculated for partial invoicing)
update_recordSet vendAccruedPurchasesTmp_NA setting
CostAmountPhysical = (vendAccruedPurchasesTmp_NA.ValueMST / vendAccruedPurchasesTmp_NA.ReceivedQuantity) * (vendAccruedPurchasesTmp_NA.ReceivedQuantity – partialInvoiced.PartiallyInvoicedQuantity),
CostAmountPosted = 0,
qty = (vendAccruedPurchasesTmp_NA.ReceivedQuantity – partialInvoiced.PartiallyInvoicedQuantity),
Voucher = ”
where vendAccruedPurchasesTmp_NA.ReceivedQuantity != 0
join partialInvoiced where
partialInvoiced.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine;
// Any packing slip that is prior to the cut-off date and has invoices that are only after the cut-off date should be updated.
// If there are invoices prior the cut-off date, then this update does not apply.
update_recordSet vendAccruedPurchasesTmp_NA setting
CostAmountPosted = 0
where vendAccruedPurchasesTmp_NA.ReceivedQuantity != 0
join qtyMatched where
qtyMatched.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine
join vendInvoiceTrans where
vendInvoiceTrans.SourceDocumentLine == qtyMatched.InvoiceSourceDocumentLIne
&& vendInvoiceTrans.InvoiceDate > cutOffDate
notExistsjoin partialInvoiced where
partialInvoiced.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine;
// Any packing slip that is prior to the cut-off date and has invoices that are before the cut-off date should be updated.
update_recordSet vendAccruedPurchasesTmp_NA setting
DateFinancial = dateNull()
where vendAccruedPurchasesTmp_NA.ReceivedQuantity != 0
join partialInvoiced where
partialInvoiced.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine;
// Update Costs and quantities for packing slips that are after the cut-off, but invoices that are before the cut-off
update_recordSet vendAccruedPurchasesTmp_NA setting
CostAmountPhysical = (vendAccruedPurchasesTmp_NA.ValueMST / vendAccruedPurchasesTmp_NA.ReceivedQuantity) * partialInvoicedBeforeCutOff.PartiallyInvoicedQuantity,
CostAmountPosted = (vendAccruedPurchasesTmp_NA.ValueMST / vendAccruedPurchasesTmp_NA.ReceivedQuantity) * partialInvoicedBeforeCutOff.PartiallyInvoicedQuantity,
qty = partialInvoicedBeforeCutOff.PartiallyInvoicedQuantity
where vendAccruedPurchasesTmp_NA.ReceivedQuantity != 0
join partialInvoicedBeforeCutOff where
partialInvoicedBeforeCutOff.PackingSlipSourceDocumentLine == vendAccruedPurchasesTmp_NA.PackingSlipSourceDocumentLine;
// Accrual (has to be calculated *after* CostAmountPosted is populated)
update_recordSet vendAccruedPurchasesTmp_NA setting
Accrual = vendAccruedPurchasesTmp_NA.CostAmountPhysical – vendAccruedPurchasesTmp_NA.CostAmountPosted
where vendAccruedPurchasesTmp_NA.DatePhysical <= cutOffDate;
update_recordSet vendAccruedPurchasesTmp_NA setting
Accrual = 0– vendAccruedPurchasesTmp_NA.CostAmountPosted
where vendAccruedPurchasesTmp_NA.DatePhysical > cutOffDate;
ttsbegin;
whileselect forUpdate vendAccruedPurchasesTmp_NAZ
{
select RecId from inventTransOrigin
where inventTransOrigin.InventTransId == vendAccruedPurchasesTmp_NA.InventTransID
join inventTrans
where inventTrans.InventTransOrigin == inventTransOrigin.RecId
&& inventTrans.VoucherPhysical == vendAccruedPurchasesTmp_NA.VoucherPhysical;
if (inventTrans.DatePhysical && inventTrans.DateFinancial)
{
if (inventTrans.DatePhysical < inventTrans.DateFinancial)
{
accrual = inventTrans.costAmountPhysExclStdAdjustment();
}
else
{
if (inventTrans.DatePhysical > inventTrans.DateFinancial)
{
accrual = -inventTrans.costAmountPhysExclStdAdjustment();
}
else
{
accrual = -inventTrans.CostAmountPosted;
}
}
}
else
{
if (inventTrans.DatePhysical)
{
accrual = inventTrans.costAmountPhysExclStdAdjustment();
}
if (inventTrans.DateFinancial)
{
accrual = -inventTrans.CostAmountPosted;
}
}
vendAccruedPurchasesTmp_NA.Accrual = accrual;
vendAccruedPurchasesTmp_NA.update();
}
ttsCommit;
}
Disclaimer. The described code changes are for your information only. Microsoft only supports installation of the packaged hotfix, and we do not recommend that you attempt to implement similar changes manually.