The CFDI Complement for Payment Reception version 2.0 (Complemento para recepción de Pagos 2.0) requires several computed totals that aggregate taxes across allDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/eclipxe13/CfdiUtils/llms.txt
Use this file to discover all available pages before exploring further.
Pago and DocumentoRelacionado nodes. These calculations involve currency conversion factors (TipoCambioP, EquivalenciaDR), multiple tax types, and decimal truncation rules that are difficult to implement correctly using ordinary floating-point arithmetic.
CfdiUtils\SumasPagos20\Calculator performs all these calculations precisely, and CfdiUtils\SumasPagos20\PagosWriter writes the results back into the corresponding XML nodes. The static convenience method PagosWriter::calculateAndPut() combines both steps in a single call.
The three groups of data that get calculated and written are:
Totales— the aggregate tax totals written as attributes of thepago20:Totalesnode.Pago\ImpuestosP— per-payment tax nodes derived from the related document taxes.Pago@Monto— the minimum payment amount if the attribute was not already set.
The
ext-bcmath PHP extension is required for this utility. All decimal arithmetic in the Pagos 2.0 calculator is delegated to BCMath (Arbitrary Precision Mathematics) to avoid the rounding and truncation errors inherent in IEEE 754 floating-point. Ensure extension=bcmath is enabled in your php.ini before using this utility.Quick Start
Calculator Class
CfdiUtils\SumasPagos20\Calculator is the calculation engine. Construct it when you need control over precision or supported currencies.
Constructor parameters
Number of decimal places used when rounding per-payment tax amounts (applied to each
Pago\ImpuestosP value). Must be between 0 and 6 — values outside this range are clamped automatically.A
Currencies instance mapping currency codes to their decimal precision. Used when computing the minimum Pago@Monto via truncation. Add any foreign currencies used in your payments.calculate(NodeInterface $nodePagos): Pagos
Reads all pago20:Pago children of $nodePagos, processes each pago20:DoctoRelacionado and its ImpuestosDR descendants, and returns a Pagos result object containing the computed Totales and per-Pago data.
The returned Pagos object is immutable and JSON-serializable — useful for logging or debugging.
Available Totals
TheTotales object returned by $result->getTotales() exposes the following getters. Any that return null indicate no data exists for that field (i.e. the corresponding XML attribute should be omitted).
Transfer taxes (IVA)
Corresponds to XML attribute
TotalTrasladosBaseIVA16. Aggregate base amount for IVA at 16 %.Corresponds to XML attribute
TotalTrasladosImpuestoIVA16. Aggregate tax amount for IVA at 16 %.Corresponds to XML attribute
TotalTrasladosBaseIVA8. Aggregate base amount for IVA at 8 %.Corresponds to XML attribute
TotalTrasladosImpuestoIVA8. Aggregate tax amount for IVA at 8 %.Corresponds to XML attribute
TotalTrasladosBaseIVA0. Aggregate base amount for IVA at 0 %.Corresponds to XML attribute
TotalTrasladosImpuestoIVA0. Aggregate tax amount for IVA at 0 %.Corresponds to XML attribute
TotalTrasladosBaseIVAExento. Aggregate base amount for exempt IVA entries.Withholding taxes (retenciones)
Corresponds to XML attribute
TotalRetencionesIVA. Total IVA withheld across all payments (impuesto 002).Corresponds to XML attribute
TotalRetencionesISR. Total ISR withheld across all payments (impuesto 001).Corresponds to XML attribute
TotalRetencionesIEPS. Total IEPS withheld across all payments (impuesto 003).Grand total
Corresponds to XML attribute
MontoTotalPagos. Sum of all Pago@Monto values converted to MXN and rounded to 2 decimal places.The Decimal Type
All monetary values inside the result objects are instances of CfdiUtils\SumasPagos20\Decimal — a BCMath-backed arbitrary-precision decimal type.
Decimal is designed for internal use — you will typically only read its string representation when inspecting computed values.
Accessing Per-Payment Results
ThePagos result object also gives you access to the computed data for each individual payment. Use Impuestos::getTraslados() and Impuestos::getRetenciones() to iterate safely over all taxes, or use find() to look up a specific tax without risking an exception.
Impuestos::getTraslado(string $impuesto, string $tipoFactor, string $tasaCuota): Impuesto and Impuestos::getRetencion(string $impuesto): Impuesto throw a LogicException if the requested tax does not exist. Use getTraslados() / getRetenciones() to iterate all entries without risk, or wrap the call in a try/catch if you need to look up a specific tax that may be absent.Required Input Data
Before callingcalculate(), the Pagos element must already contain the following data:
Using PagosWriter Directly
If you already have aPagos result object, PagosWriter lets you write it independently:
PagosWriter::put(Pagos $result): void performs two operations:
- Writes
pago20:Totales— removes any existingTotalesnode and adds a new one with the calculated attributes (MontoTotalPagos,TotalRetencionesIVA,TotalTrasladosBaseIVA16, etc.). - Writes each
pago20:Pago\ImpuestosP— removes any existingImpuestosPnode and populatesRetencionesPandTrasladosPchildren from the calculated per-payment taxes.
PagosWriter only writes the Pago@Monto attribute when the attribute is not already set on the element. If you have manually set a Monto that is higher than the computed minimum, it will be preserved.Debugging with JSON
All result objects implementJsonSerializable, making them easy to inspect:
BCMath and Decimal Precision
Working with payment totals requires decimal arithmetic that ordinary PHP floats cannot handle reliably. For example, truncating12345.6789 to 2 decimal places with floats can yield 12345.67 or 12345.68 depending on the internal representation.
Calculator uses BCMath for all arithmetic — addition, multiplication, division, truncation, and rounding — treating every number as a string of digits throughout the computation. Final totals are rounded to 2 decimal places (MXN) and per-payment taxes to $paymentTaxesPrecision decimal places.
For the full workflow of creating a CFDI with a Pagos 2.0 complement — including building the Pagos element, adding Pago and DoctoRelacionado nodes, and sealing the document — see the Creating CFDI with Complements guide.