{"version":3,"file":"nfe.cjs","names":[],"sources":["../../src/br/nfe.ts"],"sourcesContent":["import type { UF } from \"./locations\";\n\n/**\n * A 44-digit fiscal access key could not be read.\n *\n * Its own class so a scanner screen can tell a bad key apart from a bug and show\n * the message to the operator unchanged.\n */\nexport class ChaveNFeError extends Error {\n    constructor(message: string) {\n        super(message);\n        this.name = \"ChaveNFeError\";\n    }\n}\n\n/** A fiscal access key taken apart. */\nexport interface ChaveNFe {\n    /** Federative unit of the issuer, resolved from {@link cUF}. */\n    uf: UF;\n    /** The raw 2-digit IBGE code, positions 1-2. */\n    cUF: string;\n    /** Positions 3-6, `AAMM` — the two-digit year and the month of issue. */\n    anoMes: string;\n    /** Four-digit year derived from {@link anoMes}. */\n    ano: number;\n    /** Month of issue, 1-12. */\n    mes: number;\n    /** Positions 7-20, the issuer's CNPJ. */\n    cnpj: string;\n    /** Positions 21-22, `mod`. `\"55\"` is an NF-e, `\"65\"` an NFC-e. */\n    modelo: string;\n    /** Human label for {@link modelo}, or `null` for a model outside the table. */\n    modeloLabel: string | null;\n    /** Positions 23-25. */\n    serie: string;\n    /** Positions 26-34, `nNF`. */\n    numero: string;\n    /** Position 35, `tpEmis`. */\n    tipoEmissao: string;\n    /** Human label for {@link tipoEmissao}, or `null` for a value outside the table. */\n    tipoEmissaoLabel: string | null;\n    /** Positions 36-43, `cNF` — the issuer's random code. */\n    codigoNumerico: string;\n    /** Position 44, `cDV`. */\n    dv: string;\n}\n\n/**\n * IBGE code of each federative unit, as `cUF` carries it.\n *\n * Only the numeric codes live here — the acronyms are the `UF` union from\n * `./locations`, so a state added or renamed there flows through. Ported from the\n * IBGE table of \"códigos dos municípios\" (the two leading digits of every\n * municipality code), which is the same table the NF-e manual points at.\n */\nconst UF_BY_CODE: Record<string, UF> = {\n    \"11\": \"RO\",\n    \"12\": \"AC\",\n    \"13\": \"AM\",\n    \"14\": \"RR\",\n    \"15\": \"PA\",\n    \"16\": \"AP\",\n    \"17\": \"TO\",\n    \"21\": \"MA\",\n    \"22\": \"PI\",\n    \"23\": \"CE\",\n    \"24\": \"RN\",\n    \"25\": \"PB\",\n    \"26\": \"PE\",\n    \"27\": \"AL\",\n    \"28\": \"SE\",\n    \"29\": \"BA\",\n    \"31\": \"MG\",\n    \"32\": \"ES\",\n    \"33\": \"RJ\",\n    \"35\": \"SP\",\n    \"41\": \"PR\",\n    \"42\": \"SC\",\n    \"43\": \"RS\",\n    \"50\": \"MS\",\n    \"51\": \"MT\",\n    \"52\": \"GO\",\n    \"53\": \"DF\",\n};\n\n/** The document models that share the 44-digit key layout. */\nconst MODELO_LABELS: Record<string, string> = {\n    \"55\": \"NF-e\",\n    \"57\": \"CT-e\",\n    \"58\": \"MDF-e\",\n    \"59\": \"SAT-CF-e\",\n    \"63\": \"BP-e\",\n    \"65\": \"NFC-e\",\n    \"66\": \"NF3e\",\n    \"67\": \"CT-e OS\",\n};\n\n/** `tpEmis` values from the NF-e manual. */\nconst TIPO_EMISSAO_LABELS: Record<string, string> = {\n    \"1\": \"Normal\",\n    \"2\": \"Contingência FS-IA\",\n    \"3\": \"Contingência SCAN\",\n    \"4\": \"Contingência DPEC/EPEC\",\n    \"5\": \"Contingência FS-DA\",\n    \"6\": \"Contingência SVC-AN\",\n    \"7\": \"Contingência SVC-RS\",\n    \"9\": \"Contingência off-line (NFC-e)\",\n};\n\n/** Weight cycle of the módulo 11 check digit, applied right to left. */\nconst DV_WEIGHT_FIRST = 2;\nconst DV_WEIGHT_LAST = 9;\n\n/** Length of the key, and of the body the check digit protects. */\nconst CHAVE_LENGTH = 44;\nconst CHAVE_BODY_LENGTH = 43;\n\n/** Century the two-digit `AAMM` year resolves into. NF-e went live in 2006. */\nconst CHAVE_YEAR_BASE = 2000;\n\n/** Digits of a key that may carry spaces or dots from a copy-paste. */\nfunction digits(value: string): string {\n    return value.replace(/\\D/g, \"\");\n}\n\n/**\n * The check digit a 43-digit key body requires.\n *\n * Módulo 11: each digit is multiplied by weights cycling `2…9` from right to\n * left, the products are summed, and the digit is `11 - (sum mod 11)` — except\n * that a remainder of `0` or `1` yields `0`, since `11` and `10` do not fit one\n * position.\n *\n * Note this is the **fiscal** flavour of módulo 11. The cobrança boleto resolves\n * those same remainders to `1`; see `mod11DacCobranca` in `./boleto`.\n *\n * @param body - The first 43 digits of the key.\n * @returns The check digit, 0-9.\n * @throws {ChaveNFeError} When `body` is not exactly 43 digits.\n */\nexport function chaveNFeCheckDigit(body: string): number {\n    if (!new RegExp(`^\\\\d{${CHAVE_BODY_LENGTH}}$`).test(body)) {\n        throw new ChaveNFeError(\n            `The check digit is computed over ${CHAVE_BODY_LENGTH} digits, got ${body.length}.`,\n        );\n    }\n    const span = DV_WEIGHT_LAST - DV_WEIGHT_FIRST + 1;\n    let sum = 0;\n    for (let index = 0; index < body.length; index += 1) {\n        const fromRight = body.length - 1 - index;\n        sum += Number(body[index]) * (DV_WEIGHT_FIRST + (fromRight % span));\n    }\n    const remainder = sum % 11;\n    return remainder === 0 || remainder === 1 ? 0 : 11 - remainder;\n}\n\n/**\n * Whether a fiscal access key is well formed.\n *\n * Three things have to hold: 44 digits, a `cUF` that is a real federative unit,\n * and a check digit that recomputes. It says nothing about whether the document\n * exists or was authorised — only SEFAZ can answer that — but it catches the\n * failure that actually happens, a key transcribed by hand or truncated by a\n * spreadsheet.\n *\n * @param chave - The key, with or without the spaces a DANFE prints.\n * @returns `true` when all three hold.\n *\n * @example\n * if (!validateChaveNFe(input)) setError(\"Chave inválida.\");\n */\nexport function validateChaveNFe(chave: string): boolean {\n    const raw = digits(chave);\n    if (raw.length !== CHAVE_LENGTH) return false;\n    if (UF_BY_CODE[raw.slice(0, 2)] === undefined) return false;\n    return String(chaveNFeCheckDigit(raw.slice(0, CHAVE_BODY_LENGTH))) === raw.slice(43);\n}\n\n/**\n * Read a 44-digit fiscal access key into its fields.\n *\n * The layout is fixed and shared by every document type that carries a key —\n * NF-e, NFC-e, CT-e, MDF-e — so `modelo` is what tells you which one you are\n * holding, not the length.\n *\n * ```text\n * 35 2601 12345678000195 55 001 000000123 1 12345678 4\n * cUF AAMM CNPJ           mod série nNF    tp cNF     cDV\n * ```\n *\n * @param chave - The key, with or without the spaces a DANFE prints.\n * @returns The parsed key.\n * @throws {ChaveNFeError} On a length other than 44, an unknown `cUF`, a month\n * outside 1-12, or a check digit that does not recompute.\n *\n * @example\n * const { uf, cnpj, numero, modeloLabel } = parseChaveNFe(scanned);\n */\nexport function parseChaveNFe(chave: string): ChaveNFe {\n    const raw = digits(chave);\n    if (raw.length !== CHAVE_LENGTH) {\n        throw new ChaveNFeError(`An access key has ${CHAVE_LENGTH} digits, got ${raw.length}.`);\n    }\n\n    const cUF = raw.slice(0, 2);\n    const uf = UF_BY_CODE[cUF];\n    if (uf === undefined) {\n        throw new ChaveNFeError(`${cUF} is not an IBGE code for a federative unit.`);\n    }\n\n    const anoMes = raw.slice(2, 6);\n    const mes = Number(anoMes.slice(2, 4));\n    if (mes < 1 || mes > 12) {\n        throw new ChaveNFeError(`Month ${anoMes.slice(2, 4)} in AAMM is not a month.`);\n    }\n\n    const dv = raw.slice(43);\n    const expected = chaveNFeCheckDigit(raw.slice(0, CHAVE_BODY_LENGTH));\n    if (String(expected) !== dv) {\n        throw new ChaveNFeError(`Check digit is ${dv}, recomputed ${expected}.`);\n    }\n\n    const modelo = raw.slice(20, 22);\n    const tipoEmissao = raw.slice(34, 35);\n    return {\n        uf,\n        cUF,\n        anoMes,\n        ano: CHAVE_YEAR_BASE + Number(anoMes.slice(0, 2)),\n        mes,\n        cnpj: raw.slice(6, 20),\n        modelo,\n        modeloLabel: MODELO_LABELS[modelo] ?? null,\n        serie: raw.slice(22, 25),\n        numero: raw.slice(25, 34),\n        tipoEmissao,\n        tipoEmissaoLabel: TIPO_EMISSAO_LABELS[tipoEmissao] ?? null,\n        codigoNumerico: raw.slice(35, 43),\n        dv,\n    };\n}\n\n/**\n * Group a key in blocks of four, the way a DANFE prints it.\n *\n * @param chave - The key, masked or not.\n * @returns Eleven groups of four digits separated by spaces, or the input\n * unchanged when it is not 44 digits — this is a display helper, not a validator.\n *\n * @example\n * formatChaveNFe(\"35260112345678000195550010000001231123456784\");\n * // \"3526 0112 3456 7800 0195 5500 1000 0001 2311 2345 6784\"\n */\nexport function formatChaveNFe(chave: string): string {\n    const raw = digits(chave);\n    if (raw.length !== CHAVE_LENGTH) return chave;\n    return raw.replace(/(\\d{4})(?=\\d)/g, \"$1 \");\n}\n"],"mappings":"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"}