Features/494919 master mx cfdi rounding e invoice docs#9697
Conversation
…tests' of https://github.com/microsoft/BCApps into bugs/639734-master-Disable-mx-cdfi-date-boundary-flaky-tests
…r de igualdad exacta
…adas al fisco. Creacion de test relacionados al caso
| '0000C72', StrSubstNo(StampReqMsg, GetDocTypeTextFromDatabaseId(DocumentHeaderRecordRef.Number)), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', MXElectronicInvoicingTok); | ||
| CurrencyDecimalPlaces := GetCurrencyDecimalPlaces(TempDocumentHeader."Currency Code"); | ||
|
|
||
| // Recalculate SubTotal to match Σ(Importe) as written in XML (CFDI40108 compliance) |
There was a problem hiding this comment.
The new SubTotal-recalculation comment in RequestStamp contains a corrupted/mojibake byte sequence (“╬u”, hex E2 95 AC C3 BA) where a Sigma summation symbol was clearly intended (“Recalculate SubTotal to match Σ(Importe) as written in XML”). This indicates an encoding mishap when the comment was authored (e.g. a copy-paste through a lossy encoding round-trip) and leaves unreadable garbage characters permanently committed to the source file. It is cosmetic but should be fixed before merge since it will render as mangled text in every editor/diff viewer and could trip encoding-sensitive tooling.
| // Recalculate SubTotal to match Σ(Importe) as written in XML (CFDI40108 compliance) | |
| // Recalculate SubTotal to match Σ(Importe) as written in XML (CFDI40108 compliance) |
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4
|
|
||
| RoundingModel := NewRoundingModel; | ||
| RequestStamp(DocumentHeaderRecordRef, Prepayment, Reverse); | ||
| // Pre-validate locally to find the best rounding model only after default model failed |
There was a problem hiding this comment.
The new rounding fallback loop retries stamping after PAC errors CFDI40108/CFDI40110/CFDI40111/CFDI40119/CFDI40167, but it does not emit any telemetry that a retry happened, which rounding model was selected, or that all fallback models were exhausted. Telemetry will only show the generic request/success or final failure events from RequestStamp, so support cannot distinguish a first-pass success from a recovered fallback path or diagnose which PAC rejection triggered the retry. Add a dedicated retry/fallback event around this branch, including the original error code and chosen rounding model, and consider a terminal event when every fallback model fails.
Agent judgement — not directly backed by a BCQuality knowledge article.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4
|
|
||
| [PageHandler] | ||
| [Scope('OnPrem')] | ||
| procedure ErrorMessagesHandler(var ErrorMessages: TestPage "Error Messages") |
There was a problem hiding this comment.
RequestStampRaisesNoRelationDocsErrorWhenCFDIRelation04 verifies the 'No relation documents' error by adding a new [PageHandler] ErrorMessagesHandler that re-raises ErrorMessages.Description.Value() as an Error so the outer asserterror can catch it. The same codeunit already has an established pattern for this exact scenario shape (e.g. RequestStampMissedCFDIRelationsForReplacementSalesInvoice) that uses ErrorMessages.Trap() before the asserterror and then filters/asserts directly on the trapped TestPage, with no extra handler needed. Introducing a second, different mechanism for verifying the same kind of Error Messages page result adds an extra handler and indirection without added test value, and diverges from the file's own convention.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.15.4
ISSUE
When requesting a stamp (Request Stamp) on sales invoices in the Mexican localization of Business Central, the generated CFDI XML produced rounding mismatches in SubTotal and per-line tax amounts, causing PAC validation errors:
CFDI40108 – SubTotal does not equal the sum of line Importe values
CFDI40167 – Per-line tax Importe does not equal
Round(Base × TasaOCuota, 6)
This occurred primarily when:
The invoice contained multiple lines (e.g., 11+)
Unit prices and quantities produced amounts where standard rounding introduced accumulated differences
Retention lines were present alongside regular lines
CAUSE
The logic responsible for calculating SubTotal in the CFDI XML did not recalculate the value as the sum of individually rounded line Importe values (rounded to 6 decimal places).
Instead, it used the aggregated amount directly, which could differ from the SAT-expected value (Σ Round(Importe, 0.000001)).
Additionally, the rounding fallback mechanism attempted models sequentially after PAC rejection (Model1 → Model2 → Model3 → Model4), which was inefficient and could still fail when no local pre-validation was performed to identify a valid rounding model before calling the PAC.
SOLUTION
Changes implemented in EInvoiceMgt.Codeunit.al:
SubTotal recalculation for CFDI40108 compliance
Added logic in RequestStamp to recalculate SubTotal as
Σ Round(Importe, 0.000001) for non-retention lines, ensuring consistency with the values written per line in the XML.
Total recalculation for CFDI40119 consistency
After recalculating SubTotal, Total is recomputed as:
SubTotal - Descuento + Trasladados - Retenidos.
Rounding model pre-validation (FindValidRoundingModel)
Performs local validation across available rounding models (0–3) before sending the document to the PAC, selecting a model that does not trigger CFDI40167 validation errors per line.
Unified fallback mechanism (RequestStampWithRoundingFallback)
Replaces the sequential call pattern with a single procedure that:
Local tax validation (ValidateDocumentAmountsLocal)
Validates that each line's tax Importe equals:
Round(Base × VAT% / 100, 0.000001)
State reset before stamp requests
Added Clear(EInvoiceCommunication) to prevent residual state between retries.
TESTS
Added MX AL tests in codeunit 144000 "MX CFDI Unit Test" to validate the fix and prevent regressions:
RequestStampSalesInv11LinesDoesNotRaiseCFDI40108
Validates that CFDI40108 is not raised during RequestStamp execution for a posted sales invoice with 11 lines (Qty = 1, Unit Prices 90–100, VAT 16%).
RequestStampFallbackToAlternativeRoundingModel
Validates that CFDI40167 is not raised during RequestStamp execution in scenarios with quantities that introduce rounding differences.
RequestStampRaisesNoRelationDocsErrorWhenCFDIRelation04
Regression coverage: validates that non-rounding errors (e.g., missing relation documents for CFDI Relation '04') are raised as expected.
RequestStampRetentionLinesExcludedFromSubTotal
Validates that CFDI40108 is not raised during RequestStamp execution when retention lines (Retention Attached to Line No. <> 0) are present.
SubTotalEqualsRoundedSumOfLineImportes
Unit test validating that CreateTempDocument produces a SubTotal equal to
Σ Round(Amount + Line Discount Amount, 0.000001) for all non-retention lines.
Fixes:
AB#638201
Slice 494919: [RegF][Vendor] MX CFDI: Rounding in electronic invoice documents.