Saltar al contenido
dte-sdk

calculateTotals()

Calcula los montos neto, exento, IVA y total en pesos chilenos enteros para un documento o una lista de líneas de detalle.

Pruébalo#

Pruébalo — arma un documento

RUT del receptor válidotrue
totals.net$120.000
totals.exempt$0
totals.vat (19%)$22.800
totals.total$142.800

Vista previa de toXml() — sin firma ni TED

<DTE version="1.0">
  <Documento ID="F1024T33">
    <Encabezado>
      <IdDoc>
        <TipoDTE>33</TipoDTE>
        <Folio>1024</Folio>
        <FchEmis>2026-10-30</FchEmis>
      </IdDoc>
      <Emisor>
        <RUTEmisor>76123456-0</RUTEmisor>
        <RznSoc>Arrow Software SpA</RznSoc>
      </Emisor>
      <Receptor>
        <RUTRecep>77654321-7</RUTRecep>
      </Receptor>
      <Totales>
        <MntNeto>120000</MntNeto>
        <TasaIVA>19</TasaIVA>
        <IVA>22800</IVA>
        <MntTotal>142800</MntTotal>
      </Totales>
    </Encabezado>
    <Detalle>
      <NroLinDet>1</NroLinDet>
      <NmbItem>Licencia anual</NmbItem>
      <QtyItem>1</QtyItem>
      <PrcItem>120000</PrcItem>
      <MontoItem>120000</MontoItem>
    </Detalle>
  </Documento>
</DTE>

Uso básico#

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([{ name: 'Licencia anual', quantity: 1, unitPrice: 120000 }])
// { net: 120000, exempt: 0, vatRate: 19, vat: 22800, total: 142800 }

Firma de tipo#

TypeScript
function calculateTotals(dte: Dte): Totals
function calculateTotals(
  items: LineItem[],
  options?: { type?: DteType; vatRate?: number; grossPrices?: boolean },
): Totals
 
interface Totals {
  net: number
  exempt: number
  vatRate: number
  vat: number
  total: number
}

Parámetros#

  • dte (Dte) - Un documento creado con createDte(). Se usan su tipo y sus líneas, y el resultado es igual a dte.totals.
  • items (LineItem[]) - Las líneas de detalle a totalizar, con la misma forma que en createDte().
  • options (opcional, solo junto con items)
    • type (DteType) - Aplica las reglas de ese tipo de documento. Sin él, las líneas se totalizan como un documento afecto común: precios netos, IVA por encima.
    • vatRate (number, por defecto: VAT_RATE, que es 19) - Tasa de IVA como porcentaje.
    • grossPrices (boolean) - Si los precios unitarios ya incluyen IVA. Por defecto es true en boletas (tipo 39) y false en todo lo demás.

Valor de retorno#

Retorna un objeto Totals. Todos los montos son enteros en CLP:

  • net - Suma de las líneas afectas (antes de IVA)
  • exempt - Suma de las líneas exentas
  • vatRate - La tasa aplicada, como porcentaje
  • vat - El monto de IVA
  • total - net + vat + exempt

Las líneas inválidas lanzan un DteError con código INVALID_AMOUNT, con las mismas reglas que createDte().

Reglas de redondeo#

El peso chileno no tiene decimales, así que cada monto se redondea al peso más cercano, con las mitades hacia arriba (half-up). El orden de las operaciones importa:

  1. Cada línea se redondea por separado. El monto de una línea es round(quantity × unitPrice × (1 − discountPercent / 100)), redondeado antes de sumar las líneas.
  2. El IVA se calcula una sola vez, sobre el neto ya sumado: vat = round(net × vatRate / 100).
  3. Las líneas exentas (exempt: true) se suman a exempt y nunca llevan IVA.
  4. Los documentos exentos (tipos 34 y 41) tratan todas las líneas como exentas: net y vat quedan en 0.
  5. Las boletas (tipo 39) usan precios brutos por defecto. Los precios ya incluyen IVA, así que el total es la suma de las líneas y el IVA se desglosa desde ahí: net = round(total / 1.19) y vat = total − net. El neto más el IVA siempre suma lo que pagó el cliente.

Redondeo por línea#

Dos líneas de 1,5 × 999 dan 1498,5 cada una, y cada una se redondea hacia arriba a 1499 antes de sumarlas:

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([
  { name: 'Cable UTP (m)', quantity: 1.5, unitPrice: 999 },
  { name: 'Cable HDMI (m)', quantity: 1.5, unitPrice: 999 },
])
// each line: 1.5 × 999 = 1498.5 → 1499
// net: 1499 + 1499 = 2998 (rounding the sum instead would give 2997)
// vat: round(2998 × 0.19) = round(569.62) = 570
// { net: 2998, exempt: 0, vatRate: 19, vat: 570, total: 3568 }

Descuentos#

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([
  { name: 'Soporte mensual', quantity: 3, unitPrice: 9990, discountPercent: 15 },
])
// line: 3 × 9990 × 0.85 = 25474.5 → 25475 (half-up)
// vat: round(25475 × 0.19) = round(4840.25) = 4840
// { net: 25475, exempt: 0, vatRate: 19, vat: 4840, total: 30315 }

Líneas exentas#

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([
  { name: 'Licencia anual', quantity: 1, unitPrice: 120000 },
  { name: 'Soporte mensual', quantity: 3, unitPrice: 9990, discountPercent: 15 },
  { name: 'Curso de capacitación', quantity: 2, unitPrice: 45000, exempt: true },
])
// net:    120000 + 25475 = 145475
// vat:    round(145475 × 0.19) = round(27640.25) = 27640
// exempt: 2 × 45000 = 90000
// { net: 145475, exempt: 90000, vatRate: 19, vat: 27640, total: 263115 }

Documentos exentos (34 y 41)#

TypeScript
import { calculateTotals } from 'dte-sdk'
 
const items = [{ name: 'Licencia anual', quantity: 1, unitPrice: 120000 }]
 
const totals = calculateTotals(items, { type: 34 })
totals.net    // 0
totals.exempt // 120000
totals.vat    // 0
totals.total  // 120000

Boletas (39)#

En una boleta ingresas el precio que ve el cliente, con IVA incluido:

TypeScript
import { calculateTotals } from 'dte-sdk'
 
calculateTotals([{ name: 'Licencia anual', quantity: 1, unitPrice: 142800 }], { type: 39 })
// net: round(142800 / 1.19) = 120000, vat: 142800 − 120000 = 22800
// { net: 120000, exempt: 0, vatRate: 19, vat: 22800, total: 142800 }
 
calculateTotals([{ name: 'Café de grano 250 g', quantity: 2, unitPrice: 4990 }], { type: 39 })
// total: 9980, net: round(8386.55) = 8387, vat: 9980 − 8387 = 1593
// { net: 8387, exempt: 0, vatRate: 19, vat: 1593, total: 9980 }

Si tu catálogo guarda precios netos, desactiva los precios brutos:

TypeScript
calculateTotals([{ name: 'Licencia anual', quantity: 1, unitPrice: 120000 }], {
  type: 39,
  grossPrices: false,
})
// { net: 120000, exempt: 0, vatRate: 19, vat: 22800, total: 142800 }

Desde un documento#

TypeScript
import { calculateTotals, createDte } from 'dte-sdk'
 
const dte = createDte(input)
 
calculateTotals(dte) // same values as dte.totals

Pasar un Dte es útil en tests. Para mostrar un desglose antes de que exista el documento, como un carro de compras o una cotización, pasa las líneas directamente.

Funciones relacionadas#

  • createDte() - Construye un documento y calcula sus totales con estas reglas
  • toXml() - Mira los totales tal como aparecen en el XML