diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 23444fa3..b684d44b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,9 +73,9 @@ but the few rules below hold everywhere: they call. - `src/_internals/` holds the helpers shared between utilities (check-digit arithmetic, `mod10`/ `mod11`, TLV parsing for Pix, sanitizers). `src/_internals/constants/` holds the datasets - (banks, municipalities, CNAE, CBO, CFOP, NCM, legal natures), generated by the `scripts/` - from their official sources and refreshed by the `Update datasets` workflow through - a pull request, never edited by hand. + (banks, municipalities, CNAE, CBO, CFOP, NCM, NBS, the LC 116/2003 service list, legal natures), + generated by the `scripts/` from their official sources and refreshed by the `Update datasets` + workflow through a pull request, never edited by hand. - Utilities are synchronous, stateless and side-effect free: input in, value out, no globals, no environment access, no dynamic code. The two exceptions are `getAddressInfoByCep` and `getCepInfoByAddress`, the only utilities that do I/O: they query public CEP APIs (BrasilAPI, diff --git a/context7.json b/context7.json index 919ebd83..e92877c2 100644 --- a/context7.json +++ b/context7.json @@ -30,7 +30,7 @@ "rules": [ "The package has zero runtime dependencies and ships as ESM plus a UMD build; nothing else needs to be installed to use it.", "Import from the root: import { isValidCpf } from '@brazilian-utils/brazilian-utils'. Every util is also a kebab-case subpath, e.g. '@brazilian-utils/brazilian-utils/is-valid-cpf'.", - "Use the subpaths to lazy-load the dataset-backed utils (getMunicipalities, getMunicipalityByCode, getCnae, getCbo, getCfop, isValidNcm, getBanks): each one embeds a large official table.", + "Use the subpaths to lazy-load the dataset-backed utils (getMunicipalities, getMunicipalityByCode, getCnae, getCbo, getCfop, isValidNcm, getBanks, getNbs, isValidNbs, getServiceItem, isValidServiceItem): each one embeds a large official table.", "Never import the same util from both the root and its subpath in one app: a bundler treats them as two unrelated modules and bundles the dataset twice.", "Public functions never throw on bad input (null, undefined, wrong type): isValid* return false, format* and parse* return '', single-item getters return null, list getters return [].", "The only utils that reject are the async getAddressInfoByCep (GetAddressInfoByCepError: NotFound, Validation, Service) and getCepInfoByAddress (GetCepInfoByAddressError: NotFound, Validation).", diff --git a/docs/getting-started.md b/docs/getting-started.md index 3dbe79b8..853c578b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -73,8 +73,10 @@ A few utils embed an official dataset and weigh far more than everything else co | `isValidNcm` | NCM (Nomenclatura Comum do Mercosul) codes | 114.2 KB | 24.6 KB | | `isValidCbo` · `getCbo` | CBO 2002 occupation titles | 119.1 KB | 30.6 KB | | `isValidCnae` · `getCnae` | CNAE-Subclasses 2.3 | 93.9 KB | 21.2 KB | +| `isValidNbs` · `getNbs` | NBS 2.0 (Nomenclatura Brasileira de Serviços) descriptions | 81.8 KB | 13.8 KB | | `isValidCfop` · `getCfop` | CFOP operation descriptions | 68.9 KB | 6.9 KB | | `getBanks` · `getBankByCode` · `getBankByIspb` | Banco Central STR participants (COMPE + ISPB) | 38.3 - 38.6 KB | 9.5 - 9.7 KB | +| `isValidServiceItem` · `getServiceItem` | Service list of the Lei Complementar 116/2003 | 27.2 KB | 8.9 KB | The root of the package is a single ESM module, so a bundler cannot split one of these datasets out of it: importing a heavy util from the root puts its whole dataset in your main bundle, and a dynamic `import()` of the root does not help. To lazy-load one, import it from its own subpath: diff --git a/docs/pt-br/getting-started.md b/docs/pt-br/getting-started.md index 86e5f018..a3543b4a 100644 --- a/docs/pt-br/getting-started.md +++ b/docs/pt-br/getting-started.md @@ -73,8 +73,10 @@ Alguns utilitários embutem uma base de dados oficial e pesam muito mais que tod | `isValidNcm` | códigos NCM (Nomenclatura Comum do Mercosul) | 114,2 KB | 24,6 KB | | `isValidCbo` · `getCbo` | títulos das ocupações da CBO 2002 | 119,1 KB | 30,6 KB | | `isValidCnae` · `getCnae` | CNAE-Subclasses 2.3 | 93,9 KB | 21,2 KB | +| `isValidNbs` · `getNbs` | descrições da NBS 2.0 (Nomenclatura Brasileira de Serviços) | 81,8 KB | 13,8 KB | | `isValidCfop` · `getCfop` | descrições das operações do CFOP | 68,9 KB | 6,9 KB | | `getBanks` · `getBankByCode` · `getBankByIspb` | participantes do STR do Banco Central (COMPE + ISPB) | 38,3 - 38,6 KB | 9,5 - 9,7 KB | +| `isValidServiceItem` · `getServiceItem` | lista de serviços da Lei Complementar 116/2003 | 27,2 KB | 8,9 KB | A raiz do pacote é um único módulo ESM, então o bundler não consegue separar uma dessas bases de dados dele: importar um utilitário pesado da raiz coloca a base inteira no seu bundle principal, e um `import()` dinâmico da raiz não ajuda. Para carregar sob demanda, importe do subpath próprio: diff --git a/docs/pt-br/utilities.md b/docs/pt-br/utilities.md index ab9a282c..79fa1af5 100644 --- a/docs/pt-br/utilities.md +++ b/docs/pt-br/utilities.md @@ -2855,6 +2855,100 @@ parseNcm('8471.30.12'); // '84713012' parseNcm('8471'); // '8471' (um código parcial é mantido como está) ``` +### isValidNbs + +Valida um código NBS (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que Produzam Variações no Patrimônio) contra a tabela oficial da NBS 2.0, o código que a NFS-e nacional leva em `cNBS`. + +- O código tem 9 dígitos, impressos como `N.NNNN.NN.NN`: o algarismo 1, o capítulo, a posição, os dois níveis de subposição, o item e o subitem. +- Aceita uma string com os 9 dígitos ou com a máscara, com um único separador entre os grupos e espaços opcionais nas extremidades, ou um inteiro seguro não negativo. Qualquer outra string é rejeitada em vez de ter os dígitos pinçados. +- Só códigos completos são válidos: os títulos de capítulo (`1.01`), posição (`1.0101`) e subposição (`1.0101.1`) não classificam nada por si sós. +- O ANEXO B do Sistema Nacional NFS-e lista os mesmos 920 códigos menos três (`1.0402.29.00`, `1.0403.29.00` e `1.0904.40.00`), então um código válido aqui ainda pode ser recusado pela NFS-e. + +```javascript +import { isValidNbs } from '@brazilian-utils/brazilian-utils'; + +isValidNbs('1.0101.11.00'); // true +isValidNbs('101011100'); // true +isValidNbs(101011100); // true +isValidNbs('1.0101'); // false (título de posição, não um código completo) +isValidNbs('1.9999.99.99'); // false +isValidNbs('1.0101abc11.00'); // false (não é uma forma documentada) +``` + +### formatNbs + +Formata um código NBS (Nomenclatura Brasileira de Serviços) na máscara `N.NNNN.NN.NN` em que a nomenclatura o imprime. Só a estrutura muda; use `isValidNbs` para conferir um código com a tabela. + +- Todo código NBS começa com 1, então, diferente do `formatNcm`, não há opção `pad`. +- No resto, mesmas regras de `formatCnae`: a máscara é aplicada até onde o valor vai, os caracteres fora dela são descartados e um número é lido como a string dos seus dígitos. + +```javascript +import { formatNbs } from '@brazilian-utils/brazilian-utils'; + +formatNbs('101011100'); // 1.0101.11.00 +formatNbs(101011100); // 1.0101.11.00 +formatNbs('10101'); // 1.0101 (mascarado até onde vai) +formatNbs('abc101011100'); // 1.0101.11.00 (só os dígitos são lidos) +``` + +### getNbs + +Consulta um código NBS (Nomenclatura Brasileira de Serviços) e retorna a sua descrição oficial. O resultado é um registro `Nbs`: `{ code, description }`. + +- Mesmas regras de `isValidNbs`. `code` são os 9 dígitos, sem a máscara. Retorna `null` quando o código é desconhecido ou o valor não está em uma forma documentada. + +```javascript +import { getNbs } from '@brazilian-utils/brazilian-utils'; + +getNbs('1.0101.11.00'); +// { code: '101011100', description: 'Serviços de construção de edificações residenciais de um e dois pavimentos' } + +getNbs(126050000); // { code: '126050000', description: 'Serviços domésticos' } +getNbs('1.0101'); // null (título de posição, não um código completo) +getNbs('1.9999.99.99'); // null +``` + +Fonte: [tabela da NBS 2.0 publicada pelo MDIC](https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos), aprovada pela Portaria Conjunta RFB/SCS 1.429/2018 e alterada pela Portaria Conjunta RFB/SCS 2.000/2018. + +### isValidServiceItem + +Verifica se um valor é um subitem em vigor da lista de serviços anexa à Lei Complementar 116/2003, a lista dos serviços sobre os quais incide o ISS. + +- A lei numera o subitem como o item, um ponto e dois dígitos, de `1.01` a `40.01`. +- Aceita essa forma, o item preenchido com zero (`'01.01'`) ou os dígitos puros (`'0101'`, `'101'` ou o inteiro `101`), que são os quatro primeiros dígitos do código `cTribNac` da NFS-e nacional, com espaços opcionais nas extremidades. +- O ponto é o único separador que a lei imprime entre o item e o subitem, então, ao contrário dos códigos com máscara de agrupamento impressa (`isValidCfop`, `isValidNbs`), nada mais é aceito no lugar dele e `'1-01'` é rejeitado. +- Um número só é lido quando é um inteiro seguro não negativo, então o decimal `1.01` é rejeitado: escreva a forma com ponto como string. +- Os subitens vetados (`3.01`, `7.14`, `7.15`, `13.01` e `17.07`), os títulos de item, os códigos nacionais de 6 dígitos em que um subitem se desdobra e o item 99 da lista nacional, que não faz parte da lei, não são válidos. Códigos municipais de serviço estão fora do escopo. + +```javascript +import { isValidServiceItem } from '@brazilian-utils/brazilian-utils'; + +isValidServiceItem('1.01'); // true +isValidServiceItem('01.01'); // true +isValidServiceItem('0101'); // true +isValidServiceItem(101); // true +isValidServiceItem('3.01'); // false (vetado) +isValidServiceItem('99.01'); // false (só da lista nacional, não da lei) +isValidServiceItem(1.01); // false (não é um inteiro seguro não negativo) +``` + +### getServiceItem + +Consulta um subitem da lista de serviços anexa à Lei Complementar 116/2003 e retorna a sua descrição oficial. O resultado é um registro `ServiceItem`: `{ code, description }`. + +- Mesmas regras de `isValidServiceItem`. `code` é a forma em que a lei o imprime (`'1.01'`). Retorna `null` quando o subitem é desconhecido ou o valor não está em uma forma documentada. + +```javascript +import { getServiceItem } from '@brazilian-utils/brazilian-utils'; + +getServiceItem('1.01'); // { code: '1.01', description: 'Análise e desenvolvimento de sistemas.' } +getServiceItem('0101'); // { code: '1.01', description: 'Análise e desenvolvimento de sistemas.' } +getServiceItem('40.01'); // { code: '40.01', description: 'Obras de arte sob encomenda.' } +getServiceItem('3.01'); // null (vetado) +``` + +Fonte: [Lei Complementar 116/2003](https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm) e a planilha `LISTA.SERV.NAC.` do [ANEXO B do Sistema Nacional NFS-e](https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual), a lista em vigor em formato legível por máquina. + ### isValidCfop Valida um código CFOP (Código Fiscal de Operações e Prestações) contra a tabela oficial, o Anexo II consolidado do Convênio SINIEF s/nº 1970 em vigor. diff --git a/docs/utilities.md b/docs/utilities.md index a32fbb51..cdfc4f40 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -2855,6 +2855,100 @@ parseNcm('8471.30.12'); // '84713012' parseNcm('8471'); // '8471' (a partial code is kept as written) ``` +### isValidNbs + +Check if an NBS (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que Produzam Variações no Patrimônio) code exists in the official NBS 2.0 table, the code the national NFS-e carries in `cNBS`. + +- A code has 9 digits, printed as `N.NNNN.NN.NN`: the digit 1, the chapter, the position, the two subposition levels, the item and the subitem. +- Accepts a string with the 9 digits or with the mask, with a single separator between the groups and optional surrounding whitespace, or a non-negative safe integer. Any other string is rejected instead of having its digits picked out. +- Only complete codes are valid: the chapter (`1.01`), position (`1.0101`) and subposition (`1.0101.1`) headings classify nothing by themselves. +- The ANEXO B of the Sistema Nacional NFS-e lists the same 920 codes except three (`1.0402.29.00`, `1.0403.29.00` and `1.0904.40.00`), so a code valid here can still be refused by the NFS-e. + +```javascript +import { isValidNbs } from '@brazilian-utils/brazilian-utils'; + +isValidNbs('1.0101.11.00'); // true +isValidNbs('101011100'); // true +isValidNbs(101011100); // true +isValidNbs('1.0101'); // false (a position heading, not a complete code) +isValidNbs('1.9999.99.99'); // false +isValidNbs('1.0101abc11.00'); // false (not a documented form) +``` + +### formatNbs + +Format an NBS (Nomenclatura Brasileira de Serviços) code into the `N.NNNN.NN.NN` mask the nomenclature prints. Only the structure changes; use `isValidNbs` to check a code against the table. + +- Every NBS code starts with 1, so, unlike `formatNcm`, there is no `pad` option. +- Same rules as `formatCnae` otherwise: the mask is applied as far as the value goes, characters outside it are dropped, and a number is read as the string of its digits. + +```javascript +import { formatNbs } from '@brazilian-utils/brazilian-utils'; + +formatNbs('101011100'); // 1.0101.11.00 +formatNbs(101011100); // 1.0101.11.00 +formatNbs('10101'); // 1.0101 (masked as far as it goes) +formatNbs('abc101011100'); // 1.0101.11.00 (only the digits are read) +``` + +### getNbs + +Look an NBS (Nomenclatura Brasileira de Serviços) code up and get its official description. The result is an `Nbs` record: `{ code, description }`. + +- Same rules as `isValidNbs`. `code` is the 9 digits, without the mask. Returns `null` when the code is unknown or the value is not in a documented form. + +```javascript +import { getNbs } from '@brazilian-utils/brazilian-utils'; + +getNbs('1.0101.11.00'); +// { code: '101011100', description: 'Serviços de construção de edificações residenciais de um e dois pavimentos' } + +getNbs(126050000); // { code: '126050000', description: 'Serviços domésticos' } +getNbs('1.0101'); // null (a position heading, not a complete code) +getNbs('1.9999.99.99'); // null +``` + +Source: [NBS 2.0 table published by the MDIC](https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos), approved by the Portaria Conjunta RFB/SCS 1.429/2018 and amended by the Portaria Conjunta RFB/SCS 2.000/2018. + +### isValidServiceItem + +Check if a value is a subitem in force of the service list annexed to the Lei Complementar 116/2003, the list of the services the ISS is levied on. + +- The law numbers a subitem as the item, a dot and two digits, `1.01` to `40.01`. +- Accepts that form, a zero padded item (`'01.01'`) or the bare digits (`'0101'`, `'101'` or the integer `101`), which are the first four digits of the `cTribNac` code of the national NFS-e, with optional surrounding whitespace. +- The dot is the only separator the law ever prints between the item and the subitem, so, unlike the codes with a printed grouping mask (`isValidCfop`, `isValidNbs`), nothing else is accepted in its place and `'1-01'` is rejected. +- A number is only read when it is a non-negative safe integer, so the float `1.01` is rejected: write the dotted form as a string. +- The vetoed subitems (`3.01`, `7.14`, `7.15`, `13.01` and `17.07`), the item headings, the 6 digit national codes a subitem is split into and item 99 of the national list, which is not part of the law, are not valid. Municipal service codes are out of scope. + +```javascript +import { isValidServiceItem } from '@brazilian-utils/brazilian-utils'; + +isValidServiceItem('1.01'); // true +isValidServiceItem('01.01'); // true +isValidServiceItem('0101'); // true +isValidServiceItem(101); // true +isValidServiceItem('3.01'); // false (vetoed) +isValidServiceItem('99.01'); // false (national list only, not the law) +isValidServiceItem(1.01); // false (not a non-negative safe integer) +``` + +### getServiceItem + +Look a subitem of the service list annexed to the Lei Complementar 116/2003 up and get its official description. The result is a `ServiceItem` record: `{ code, description }`. + +- Same rules as `isValidServiceItem`. `code` is the form the law prints (`'1.01'`). Returns `null` when the subitem is unknown or the value is not in a documented form. + +```javascript +import { getServiceItem } from '@brazilian-utils/brazilian-utils'; + +getServiceItem('1.01'); // { code: '1.01', description: 'Análise e desenvolvimento de sistemas.' } +getServiceItem('0101'); // { code: '1.01', description: 'Análise e desenvolvimento de sistemas.' } +getServiceItem('40.01'); // { code: '40.01', description: 'Obras de arte sob encomenda.' } +getServiceItem('3.01'); // null (vetoed) +``` + +Source: [Lei Complementar 116/2003](https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm) and the sheet `LISTA.SERV.NAC.` of the [ANEXO B of the Sistema Nacional NFS-e](https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual), the list in force in machine readable form. + ### isValidCfop Check if a CFOP (Código Fiscal de Operações e Prestações) code exists in the official table, the consolidated Anexo II of Convênio SINIEF s/nº 1970 in force. diff --git a/jsr.json b/jsr.json index 8dcaf3dd..8f3ca508 100644 --- a/jsr.json +++ b/jsr.json @@ -26,6 +26,7 @@ "./format-iban": "./src/format-iban/format-iban.ts", "./format-legal-nature": "./src/format-legal-nature/format-legal-nature.ts", "./format-license-plate": "./src/format-license-plate/format-license-plate.ts", + "./format-nbs": "./src/format-nbs/format-nbs.ts", "./format-ncm": "./src/format-ncm/format-ncm.ts", "./format-nfe-key": "./src/format-nfe-key/format-nfe-key.ts", "./format-passport": "./src/format-passport/format-passport.ts", @@ -75,12 +76,14 @@ "./get-municipalities": "./src/get-municipalities/get-municipalities.ts", "./get-municipality": "./src/get-municipality/get-municipality.ts", "./get-municipality-by-code": "./src/get-municipality-by-code/get-municipality-by-code.ts", + "./get-nbs": "./src/get-nbs/get-nbs.ts", "./get-next-business-day": "./src/get-next-business-day/get-next-business-day.ts", "./get-nfe-key-info": "./src/get-nfe-key-info/get-nfe-key-info.ts", "./get-nfse-key-info": "./src/get-nfse-key-info/get-nfse-key-info.ts", "./get-nth-business-day": "./src/get-nth-business-day/get-nth-business-day.ts", "./get-pix-key-info": "./src/get-pix-key-info/get-pix-key-info.ts", "./get-pix-payload-info": "./src/get-pix-payload-info/get-pix-payload-info.ts", + "./get-service-item": "./src/get-service-item/get-service-item.ts", "./get-state-by-cep": "./src/get-state-by-cep/get-state-by-cep.ts", "./get-state-by-ibge-code": "./src/get-state-by-ibge-code/get-state-by-ibge-code.ts", "./get-state-code-by-name": "./src/get-state-code-by-name/get-state-code-by-name.ts", @@ -114,6 +117,7 @@ "./is-valid-legal-nature": "./src/is-valid-legal-nature/is-valid-legal-nature.ts", "./is-valid-license-plate": "./src/is-valid-license-plate/is-valid-license-plate.ts", "./is-valid-mobile-phone": "./src/is-valid-mobile-phone/is-valid-mobile-phone.ts", + "./is-valid-nbs": "./src/is-valid-nbs/is-valid-nbs.ts", "./is-valid-ncm": "./src/is-valid-ncm/is-valid-ncm.ts", "./is-valid-nfe-key": "./src/is-valid-nfe-key/is-valid-nfe-key.ts", "./is-valid-nfse-key": "./src/is-valid-nfse-key/is-valid-nfse-key.ts", @@ -125,6 +129,7 @@ "./is-valid-processo-juridico": "./src/is-valid-processo-juridico/is-valid-processo-juridico.ts", "./is-valid-registro-profissional": "./src/is-valid-registro-profissional/is-valid-registro-profissional.ts", "./is-valid-renavam": "./src/is-valid-renavam/is-valid-renavam.ts", + "./is-valid-service-item": "./src/is-valid-service-item/is-valid-service-item.ts", "./is-valid-service-phone": "./src/is-valid-service-phone/is-valid-service-phone.ts", "./is-valid-suframa": "./src/is-valid-suframa/is-valid-suframa.ts", "./is-valid-vin": "./src/is-valid-vin/is-valid-vin.ts", diff --git a/reports/api/brazilian-utils.api.md b/reports/api/brazilian-utils.api.md index 51f8521e..bc7d31eb 100644 --- a/reports/api/brazilian-utils.api.md +++ b/reports/api/brazilian-utils.api.md @@ -281,6 +281,9 @@ export type FormatLegalNatureOptions = { // @public export const formatLicensePlate: (value: string) => string; +// @public +export const formatNbs: (value: string | number) => string; + // @public export const formatNcm: (value: string | number, options?: FormatNcmOptions) => string; @@ -617,6 +620,9 @@ export type GetMunicipalityOptions = GetMunicipalityParams; // @public export type GetMunicipalityParams = GetMunicipalityByCodeParams | GetMunicipalityByNameParams; +// @public +export const getNbs: (value: string | number) => Nbs | null; + // @public export const getNextBusinessDay: (date: Date, options?: BusinessDayOptions) => Date | null; @@ -635,6 +641,9 @@ export const getPixKeyInfo: (value: string) => PixKeyInfo | null; // @public export const getPixPayloadInfo: (value: string) => PixPayloadInfo | null; +// @public +export const getServiceItem: (value: string | number) => ServiceItem | null; + // @public export const getStateByCep: (value: string | number) => State | null; @@ -837,6 +846,9 @@ export type IsValidMobilePhoneOptions = { version?: PhoneVersion; }; +// @public +export const isValidNbs: (value: string | number) => boolean; + // @public export const isValidNcm: (value: string | number) => boolean; @@ -891,6 +903,9 @@ export type IsValidRegistroProfissionalParams = { // @public export const isValidRenavam: (renavam: string | number) => boolean; +// @public +export const isValidServiceItem: (value: string | number) => boolean; + // @public export const isValidServicePhone: (value: string) => boolean; @@ -931,6 +946,12 @@ export type Municipality = { stateCode: StateCode; }; +// @public +export type Nbs = { + code: string; + description: string; +}; + // @public export type NfeKeyInfo = { stateCode: StateCode; @@ -1104,6 +1125,12 @@ export type RegistroProfissionalCouncil = "OAB" | "CRM" | "CRO" | "CRP" | "CRC"; // @public export const removeAccents: (value: string) => string; +// @public +export type ServiceItem = { + code: string; + description: string; +}; + // @public export type StandardSchemaV1 = { readonly "~standard": StandardSchemaV1Props; diff --git a/scripts/data.ts b/scripts/data.ts index 850c569d..19fe2ef9 100644 --- a/scripts/data.ts +++ b/scripts/data.ts @@ -26,7 +26,9 @@ const generators = [ "cities.ts", "cnae.ts", "legal-natures.ts", + "nbs.ts", "ncm.ts", + "service-items.ts", "states.ts", ]; @@ -36,6 +38,8 @@ const generatedFiles = [ "./src/_internals/constants/cfop.ts", "./src/_internals/constants/cities.ts", "./src/_internals/constants/cnae.ts", + "./src/_internals/constants/nbs.ts", + "./src/_internals/constants/service-items.ts", "./src/_internals/constants/states.ts", "./src/is-valid-legal-nature/constants.ts", "./src/is-valid-ncm/constants.ts", diff --git a/scripts/decode-xml.ts b/scripts/decode-xml.ts new file mode 100644 index 00000000..46febeff --- /dev/null +++ b/scripts/decode-xml.ts @@ -0,0 +1,29 @@ +const XML_ENTITIES: Record = { + "&": "&", + "<": "<", + ">": ">", + """: '"', + "'": "'", +}; + +const MAXIMUM_CODE_POINT = 0x10_ff_ff; + +/** + * Decodes the five entities of XML and the numeric character references a writer other than + * Excel emits, ` ` and `é` alike. Anything else is left as it is. Shared by the xlsx + * reader and the generators that read a listing page of a government portal. + * + * @param {string} text - The text as the XML carries it. + * @returns {string} The decoded text. + */ +export const decodeXml = (text: string): string => + text.replaceAll(/&(?:amp|lt|gt|quot|apos|#\d+|#x[\da-fA-F]+);/g, (entity) => { + if (!entity.startsWith("&#")) return XML_ENTITIES[entity] ?? entity; + + const reference = entity.slice(2, -1); + const code = reference.startsWith("x") + ? Number.parseInt(reference.slice(1), 16) + : Number(reference); + + return code <= MAXIMUM_CODE_POINT ? String.fromCodePoint(code) : entity; + }); diff --git a/scripts/nbs.ts b/scripts/nbs.ts new file mode 100644 index 00000000..f0877393 --- /dev/null +++ b/scripts/nbs.ts @@ -0,0 +1,146 @@ +#!/usr/bin/env node + +import { writeFile } from "node:fs/promises"; +import { resolve } from "node:path"; + +import { fetchSortedRecord } from "./fetch-sorted-record.ts"; +import { serializeRecord } from "./serialize-record.ts"; + +const scriptsDir = import.meta.dirname; + +/** The official CSV is published in ISO-8859-1, not UTF-8. */ +const NBS_CSV_DECODER = new TextDecoder("iso-8859-1"); + +const NBS_CSV_HEADER = "NBS 2.0;DESCRIÇÃO"; + +/** + * A complete code, e.g. `1.0101.11.00`. The CSV also carries the chapter (`1.01`), position + * (`1.0101`) and subposition (`1.0101.1`) headings, which classify nothing by themselves and are + * left out of the table. + */ +const NBS_CODE_REGEX = /^\d\.\d{4}\.\d{2}\.\d{2}$/; + +/** + * Smallest number of complete codes the table yields. NBS 2.0 carries 920 and only a new version + * of the nomenclature changes that, so a result far below it means the CSV layout changed. + */ +const MINIMUM_CODES = 900; + +/** + * Splits a CSV into records. A line break inside a quoted field does not end a record, so a + * description written over two lines stays in one piece. + * @param {string} csv - The decoded CSV. + * @returns {string[]} One string per record, the line breaks between records removed. + */ +const splitRecords = (csv: string): string[] => { + const records: string[] = []; + let record = ""; + let quoted = false; + + for (const character of csv) { + if (character === '"') quoted = !quoted; + + if (character === "\n" && !quoted) { + records.push(record); + record = ""; + } else if (character !== "\r" || quoted) { + record += character; + } + } + + return [...records, record]; +}; + +/** + * Reads a field the way RFC 4180 writes it: a quoted field loses its outer quotes and every + * doubled quote inside it becomes one. + * @param {string} field - The raw field, quotes included. + * @returns {string} The text of the field, whitespace collapsed. + */ +const readField = (field: string): string => { + const trimmed = field.trim(); + + if (!trimmed.startsWith('"')) return trimmed.replaceAll(/\s+/g, " "); + + if (trimmed.length < 2 || !trimmed.endsWith('"')) { + throw new Error(`NBS CSV field ${trimmed} opens a quote it never closes`); + } + + return trimmed.slice(1, -1).replaceAll('""', '"').replaceAll(/\s+/g, " "); +}; + +/** + * Reads the `NBS 2.0;DESCRIÇÃO` rows of the official NBS 2.0 CSV. + * @param {string} csv - The decoded CSV. + * @returns {Record} One entry per complete code, keyed by its 9 digits. + */ +const parseCsv = (csv: string): Record => { + const [header, ...rows] = splitRecords(csv); + + if (header?.trim() !== NBS_CSV_HEADER) { + throw new Error(`NBS CSV header is not "${NBS_CSV_HEADER}"`); + } + + const data: Record = {}; + + for (const row of rows) { + const separator = row.indexOf(";"); + const code = row.slice(0, Math.max(separator, 0)).trim(); + const description = readField(row.slice(separator + 1)); + + if (!NBS_CODE_REGEX.test(code) || description === "") continue; + + data[code.replaceAll(".", "")] = description; + } + + return data; +}; + +const main = async (): Promise => { + const sorted = await fetchSortedRecord( + "https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/NBSa_2-0.csv", + "NBS CSV", + async (response) => { + const data = parseCsv(NBS_CSV_DECODER.decode(await response.arrayBuffer())); + + if (Object.keys(data).length < MINIMUM_CODES) { + throw new Error(`NBS CSV holds fewer than ${MINIMUM_CODES} codes`); + } + + return data; + }, + ); + + await writeFile( + resolve(scriptsDir, "..", "./src/_internals/constants/nbs.ts"), + `/** + * NBS 2.0 (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que Produzam + * Variações no Patrimônio) descriptions, indexed by the raw 9 digit code. + * + * Built from the official \`NBSa_2-0.csv\` the MDIC publishes on gov.br, a plain + * \`NBS 2.0;DESCRIÇÃO\` CSV in ISO-8859-1, the version 2.0 as amended by the Portaria Conjunta + * RFB/SCS 2.000 of 18 December 2018. Only the complete codes are kept: the chapter, position and + * subposition headings of the CSV classify nothing by themselves. + * + * Generated by \`node ./scripts/nbs.ts\`. Do not edit by hand. + * + * @see Official: https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos + * The NBS page of the MDIC, which links the CSV and the Anexo I of the Portaria. + * @see Official: https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/NBSa_2-0.csv + * The NBS 2.0 table in CSV. + */ +export const NBS_DESCRIPTIONS: Record = ${serializeRecord(sorted)}; + +/** + * Shape an NBS code has to be written in: the 9 digits, optionally split into the printed + * groups of 1, 4, 2 and 2 by a single whitespace or mask character. + */ +export const NBS_FORMAT_REGEX = /^\\d[\\s.\\-/]?\\d{4}[\\s.\\-/]?\\d{2}[\\s.\\-/]?\\d{2}$/; +`, + ); +}; + +await main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exit(1); +}); diff --git a/scripts/read-xlsx-sheet.ts b/scripts/read-xlsx-sheet.ts new file mode 100644 index 00000000..c328f0c3 --- /dev/null +++ b/scripts/read-xlsx-sheet.ts @@ -0,0 +1,325 @@ +import { inflateRawSync } from "node:zlib"; + +import { decodeXml } from "./decode-xml.ts"; + +const END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06_05_4b_50; + +const CENTRAL_DIRECTORY_SIGNATURE = 0x02_01_4b_50; + +const LOCAL_HEADER_SIGNATURE = 0x04_03_4b_50; + +const CENTRAL_DIRECTORY_HEADER_SIZE = 46; + +const LOCAL_HEADER_SIZE = 30; + +const DEFLATE = 8; + +/** Largest file the reader inflates, so a corrupt archive cannot exhaust the memory. */ +const MAXIMUM_FILE_SIZE = 64 * 1024 * 1024; + +/** + * Largest amount the files read out of one workbook may hold together. A central directory can + * list thousands of sheets, so bounding each file alone does not bound the whole read. + */ +const MAXIMUM_WORKBOOK_SIZE = 128 * 1024 * 1024; + +/** + * The part that holds the text of the cells. A workbook whose cells are all inline strings does + * not carry it, which is valid, so it is read only when the archive has it. + */ +const SHARED_STRINGS = "xl/sharedStrings.xml"; + +/** Rows a worksheet can hold, `1048576`. A reference past it is not a sheet this reader can read. */ +const MAXIMUM_ROWS = 1_048_576; + +/** Columns a worksheet can hold, `A` to `XFD`. */ +const MAXIMUM_COLUMNS = 16_384; + +const ALPHABET_LENGTH = 26; + +const CODE_BEFORE_A = 64; + +/** One file of a zip archive, still compressed. */ +type ZipEntry = { + /** The compression method of the entry, 8 for deflate and 0 for stored. */ + method: number; + /** The bytes of the entry as the archive carries them. */ + data: Buffer; +}; + +/** The entries of an archive and how much has been inflated out of it so far. */ +type Archive = { + /** Every entry, keyed by its path, left compressed. */ + files: Map; + /** Bytes read out of the archive so far, checked against `MAXIMUM_WORKBOOK_SIZE`. */ + read: number; +}; + +/** One sheet of a workbook, as `xl/workbook.xml` lists it. */ +type SheetEntry = { + /** The name of the sheet, as its tab shows it. */ + name: string; + /** The path of the worksheet part inside the archive. */ + path: string; +}; + +/** A workbook opened far enough to read any of its sheets. */ +type Workbook = { + /** The archive of the workbook. */ + archive: Archive; + /** The shared strings of the workbook. */ + strings: string[]; + /** The sheets, in the order of their tabs. */ + sheets: SheetEntry[]; +}; + +/** + * Reads the entries of a zip archive out of its central directory. ZIP64 is not supported, so + * an archive above 4 GB or with more than 65535 entries is out of reach, which no table the + * government publishes comes close to. + * @param {Buffer} archive - The whole archive. + * @returns {Archive} Every entry, keyed by its path, left compressed. + */ +const unzip = (archive: Buffer): Archive => { + let end = archive.length - 22; + + while (end >= 0 && archive.readUInt32LE(end) !== END_OF_CENTRAL_DIRECTORY_SIGNATURE) end--; + + if (end < 0) throw new Error("not a zip archive"); + + const files = new Map(); + let offset = archive.readUInt32LE(end + 16); + + for (let index = archive.readUInt16LE(end + 10); index > 0; index--) { + if (archive.readUInt32LE(offset) !== CENTRAL_DIRECTORY_SIGNATURE) { + throw new Error("the zip central directory is broken"); + } + + const method = archive.readUInt16LE(offset + 10); + const size = archive.readUInt32LE(offset + 20); + const nameLength = archive.readUInt16LE(offset + 28); + const skipped = archive.readUInt16LE(offset + 30) + archive.readUInt16LE(offset + 32); + const local = archive.readUInt32LE(offset + 42); + const nameStart = offset + CENTRAL_DIRECTORY_HEADER_SIZE; + const name = archive.toString("utf8", nameStart, nameStart + nameLength); + + if (archive.readUInt32LE(local) !== LOCAL_HEADER_SIGNATURE) { + throw new Error(`the zip entry ${name} points at no local header`); + } + + const start = + local + + LOCAL_HEADER_SIZE + + archive.readUInt16LE(local + 26) + + archive.readUInt16LE(local + 28); + + files.set(name, { method, data: archive.subarray(start, start + size) }); + offset = nameStart + nameLength + skipped; + } + + return { files, read: 0 }; +}; + +/** + * Turns the letters of a cell reference into a zero based column index: `A` is 0, `AA` is 26. + * @param {string} letters - The column letters of the reference. + * @returns {number} The zero based index of the column. + */ +const columnIndex = (letters: string): number => { + let index = 0; + + for (let position = 0; position < letters.length; position++) { + index = index * ALPHABET_LENGTH + letters.charCodeAt(position) - CODE_BEFORE_A; + } + + return index - 1; +}; + +/** + * Inflates one file of the archive and reads it as UTF-8. Only the files a caller asks for are + * inflated, which leaves the themes, the styles and the custom XML of a workbook untouched. + * @param {Archive} archive - The archive. + * @param {string} path - The path of the file inside the archive. + * @returns {string} The content of the file. + */ +const readFile = (archive: Archive, path: string): string => { + const entry = archive.files.get(path); + + if (entry === undefined) throw new Error(`the workbook has no ${path}`); + + const content = + entry.method === DEFLATE + ? inflateRawSync(entry.data, { maxOutputLength: MAXIMUM_FILE_SIZE }) + : entry.data; + + archive.read += content.length; + + if (archive.read > MAXIMUM_WORKBOOK_SIZE) { + throw new Error(`the workbook holds more than ${MAXIMUM_WORKBOOK_SIZE} bytes`); + } + + return content.toString("utf8"); +}; + +/** + * Joins the text runs of a shared string or of an inline string. A cell whose text is styled in + * pieces carries one `` per piece. The `` elements hold the phonetic reading of the + * text, not the text, so they are dropped first. + * @param {string} xml - The content of the `` or `` element. + * @returns {string} The text of the element. + */ +const joinRuns = (xml: string): string => + [...xml.replaceAll(//gs, "").matchAll(/]*>([^<]*)<\/t>/g)] + .map((run) => decodeXml(run[1])) + .join(""); + +/** + * Resolves the target of a workbook relationship into a path inside the archive. The OPC spec + * allows an absolute target (`/xl/worksheets/sheet1.xml`) and one that climbs out of the part + * folder (`../worksheets/sheet1.xml`) as well as the plain relative form. + * @param {string} target - The `Target` of the relationship. + * @returns {string} The path of the part inside the archive. + */ +const resolveTarget = (target: string): string => + decodeURIComponent(new URL(target, "file:///xl/").pathname).slice(1); + +/** + * Reads the cells of one row, placed by the column of their reference. A cell past the last + * column a worksheet can hold fails the run, so a corrupt reference cannot make the row array + * grow to its index. + * @param {string} row - The content of the `` element. + * @param {string[]} strings - The shared strings of the workbook. + * @returns {string[]} The cells of the row, an absent one as `""`. + */ +const readCells = (row: string, strings: string[]): string[] => { + const cells: string[] = []; + + for (const cell of row.matchAll(/]*?)(?:\/>|>(.*?)<\/c>)/gs)) { + const reference = /\br="([A-Z]+)\d+"/.exec(cell[1])?.[1]; + + if (reference === undefined) continue; + + const column = columnIndex(reference); + + if (column >= MAXIMUM_COLUMNS) throw new Error(`the column ${reference} is past the sheet`); + + const type = /\bt="([^"]*)"/.exec(cell[1])?.[1]; + const body = cell[2] ?? ""; + const value = /([^<]*)<\/v>/.exec(body)?.[1] ?? ""; + + if (type === "inlineStr") cells[column] = joinRuns(body); + else if (type === "s") + cells[column] = /^\d+$/.test(value) ? (strings[Number(value)] ?? "") : ""; + else cells[column] = decodeXml(value); + } + + return Array.from(cells, (cell) => cell ?? ""); +}; + +/** + * Reads the rows of a worksheet, placed by the `r` attribute of the row rather than by the + * order they are written in, so a skipped row leaves a gap instead of shifting the table. + * @param {string} sheet - The worksheet XML. + * @param {string[]} strings - The shared strings of the workbook. + * @returns {string[][]} The rows of the sheet. + */ +const readRows = (sheet: string, strings: string[]): string[][] => { + const rows: string[][] = []; + + for (const row of sheet.matchAll(/]*?)(?:\/>|>(.*?)<\/row>)/gs)) { + const index = Number(/\br="(\d+)"/.exec(row[1])?.[1] ?? rows.length + 1) - 1; + + if (index >= MAXIMUM_ROWS) throw new Error(`the row ${index + 1} is past the sheet`); + + rows[index] = readCells(row[2] ?? "", strings); + } + + return Array.from(rows, (row) => row ?? []); +}; + +/** + * Opens a workbook: its archive, its shared strings and the list of its sheets, each resolved + * through `xl/_rels/workbook.xml.rels` to the part that holds it. + * @param {Buffer} buffer - The `.xlsx` file. + * @returns {Workbook} The opened workbook. + */ +const openWorkbook = (buffer: Buffer): Workbook => { + const archive = unzip(buffer); + const relations = readFile(archive, "xl/_rels/workbook.xml.rels").matchAll( + /]*>/g, + ); + const targets = new Map(); + + for (const [tag] of relations) { + const id = /\bId="([^"]+)"/.exec(tag)?.[1]; + const target = /\bTarget="([^"]+)"/.exec(tag)?.[1]; + + if (id !== undefined && target !== undefined) targets.set(id, decodeXml(target)); + } + + const sheets: SheetEntry[] = []; + + for (const [tag] of readFile(archive, "xl/workbook.xml").matchAll(/]*>/g)) { + const name = /\bname="([^"]*)"/.exec(tag)?.[1]; + const target = targets.get(/\br:id="([^"]+)"/.exec(tag)?.[1] ?? ""); + + if (name !== undefined && target !== undefined) { + sheets.push({ name: decodeXml(name), path: resolveTarget(target) }); + } + } + + const shared = archive.files.has(SHARED_STRINGS) ? readFile(archive, SHARED_STRINGS) : ""; + const items = shared.matchAll(/]*?(?:\/>|>(.*?)<\/si>)/gs); + const strings = [...items].map((item) => joinRuns(item[1] ?? "")); + + return { archive, strings, sheets }; +}; + +/** + * Reads one sheet of an opened workbook and checks its rows against the dimension it declares. + * @param {Workbook} workbook - The opened workbook. + * @param {SheetEntry} sheet - The sheet to read. + * @returns {string[][]} The rows of the sheet. + */ +const readSheet = (workbook: Workbook, sheet: SheetEntry): string[][] => { + const content = readFile(workbook.archive, sheet.path); + const rows = readRows(content, workbook.strings); + const dimension = / { + const opened = openWorkbook(workbook); + const sheet = opened.sheets.find(({ name }) => name === sheetName); + + if (sheet === undefined) throw new Error(`the workbook has no sheet named ${sheetName}`); + + return readSheet(opened, sheet); +}; + +/** + * Reads every sheet of an `.xlsx` workbook the way `readXlsxSheet` reads one, for a workbook + * whose sheet names change from one version to the next. + * @param {Buffer} workbook - The `.xlsx` file. + * @returns {Map} The rows of each sheet, by sheet name, in the order of the tabs. + */ +export const readXlsxSheets = (workbook: Buffer): Map => { + const opened = openWorkbook(workbook); + + return new Map(opened.sheets.map((sheet) => [sheet.name, readSheet(opened, sheet)])); +}; diff --git a/scripts/serialize-record.ts b/scripts/serialize-record.ts new file mode 100644 index 00000000..55fdb404 --- /dev/null +++ b/scripts/serialize-record.ts @@ -0,0 +1,15 @@ +/** + * Serializes a record as an object literal whose entries are written in ascending key order. + * `JSON.stringify` follows the insertion order of the object, and JavaScript hoists the keys + * that are canonical array indices (`"1001"`) ahead of the others (`"0101"`), so a record built + * from sorted keys is not always emitted sorted. Writing the entries out in order keeps the + * generated tables readable and their diffs small. + * + * @param {Record} data - The entries to serialize. + * @returns {string} The object literal, sorted by key. + */ +export const serializeRecord = (data: Record): string => + `{${Object.keys(data) + .sort() + .map((key) => `${JSON.stringify(key)}:${JSON.stringify(data[key])}`) + .join(",")}}`; diff --git a/scripts/service-items.ts b/scripts/service-items.ts new file mode 100644 index 00000000..57d28315 --- /dev/null +++ b/scripts/service-items.ts @@ -0,0 +1,129 @@ +#!/usr/bin/env node + +import { writeFile } from "node:fs/promises"; +import { resolve } from "node:path"; + +import { fetchWithRetry } from "../src/_internals/fetch-with-retry/fetch-with-retry.ts"; +import { decodeXml } from "./decode-xml.ts"; +import { readXlsxSheet } from "./read-xlsx-sheet.ts"; +import { serializeRecord } from "./serialize-record.ts"; + +const scriptsDir = import.meta.dirname; + +const DOCUMENTATION_URL = + "https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual"; + +/** + * The ANEXO B is published under a file name that carries its version and date, e.g. + * `anexo_b-nbs2-lista_servico_nacional-snnfse-v1-01-20260122.xlsx`, so the link is read from the + * documentation page instead of being pinned here: a new version is picked up by the next run. + * The `href` is read as the page writes it, so it is decoded and resolved against the page before + * it is fetched, the way `scripts/ibs-cbs.ts` reads the links of the Portal da NF-e. + */ +const ANNEX_LINK_REGEX = /href="([^"]*anexo_b-nbs2-lista_servico_nacional[^"]*\.xlsx)"/i; + +const SHEET_NAME = "LISTA.SERV.NAC."; + +const SHEET_HEADER = "CÓDIGO DE TRIBUTAÇÃO NACIONAL|ITEM|SUBITEM|DESDOBRO NACIONAL|DESCRIÇÃO"; + +/** + * Item 99, "Serviços sem a incidência de ISSQN e ICMS", is an addition of the national list: the + * list annexed to the Lei Complementar 116/2003 ends at item 40. + */ +const LAST_LAW_ITEM = 40; + +/** + * Smallest number of subitems a complete list yields. The law carries 200 in force today and is + * only ever amended by another lei complementar, so a result far below it means the sheet + * changed, not that subitems were revoked. + */ +const MINIMUM_SUBITEMS = 190; + +const fetchOk = async (url: string, label: string): Promise => { + const response = await fetchWithRetry(url); + + if (!response.ok) throw new Error(`${label} request failed with status ${response.status}`); + + return response; +}; + +/** + * Reads the subitems of the law out of the national service list. The sheet prints three levels: + * the item (`SUBITEM` 0), the subitem of the law (`DESDOBRO NACIONAL` 0) and the national codes + * the Comitê Gestor splits a subitem into. Only the second level is the list annexed to the law. + * @param {string[][]} rows - The rows of the sheet, header included. + * @returns {Record} One entry per subitem, keyed by the 4 digits (`0101`). + */ +const parseSheet = (rows: string[][]): Record => { + const [header, ...body] = rows; + + if (header?.join("|") !== SHEET_HEADER) { + throw new Error(`the ${SHEET_NAME} header is not "${SHEET_HEADER}"`); + } + + const data: Record = {}; + + for (const [, item, subitem, split, description] of body) { + const isLawSubitem = Number(item) <= LAST_LAW_ITEM && Number(subitem) > 0 && split === "0"; + const text = (description ?? "").trim().replaceAll(/\s+/g, " "); + + if (!isLawSubitem || text === "") continue; + + data[`${item.padStart(2, "0")}${subitem.padStart(2, "0")}`] = text; + } + + return data; +}; + +const main = async (): Promise => { + const pageResponse = await fetchOk(DOCUMENTATION_URL, "NFS-e documentation page"); + const page = await pageResponse.text(); + const link = ANNEX_LINK_REGEX.exec(page)?.[1]; + + if (link === undefined) throw new Error("the NFS-e documentation page links no ANEXO B"); + + const annex = new URL(decodeXml(link), DOCUMENTATION_URL).href; + const workbookResponse = await fetchOk(annex, "NFS-e ANEXO B"); + const workbook = await workbookResponse.arrayBuffer(); + const data = parseSheet(readXlsxSheet(Buffer.from(workbook), SHEET_NAME)); + + if (Object.keys(data).length < MINIMUM_SUBITEMS) { + throw new Error(`the national service list holds fewer than ${MINIMUM_SUBITEMS} subitems`); + } + + await writeFile( + resolve(scriptsDir, "..", "./src/_internals/constants/service-items.ts"), + `/** + * The subitems in force of the service list annexed to the Lei Complementar 116/2003, indexed by + * the raw 4 digits of the subitem (\`0101\` for \`1.01\`), the first four digits of the national + * \`cTribNac\` code. + * + * Built from the sheet \`${SHEET_NAME}\` of the \`ANEXO_B-NBS2-LISTA_SERVICO_NACIONAL\` workbook + * of the Sistema Nacional NFS-e, which prints the list in force, vetoed subitems left out and + * the amendments of later leis complementares applied. The item headings, the national codes a + * subitem is split into and item 99, an addition of the national list, are not part of the law + * and are left out. + * + * Generated by \`node ./scripts/service-items.ts\` from \`${link.slice(link.lastIndexOf("/") + 1)}\`. + * Do not edit by hand. + * + * @see Official: https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm + * Lei Complementar 116/2003, "Lista de serviços anexa". + * @see Official: ${DOCUMENTATION_URL} + * Sistema Nacional NFS-e, current technical documentation, ANEXO B. + */ +export const SERVICE_ITEM_DESCRIPTIONS: Record = ${serializeRecord(data)}; + +/** + * Shape a subitem has to be written in: one or two digits of the item and the two of the + * subitem, with the dot the law prints between them or without it. + */ +export const SERVICE_ITEM_FORMAT_REGEX = /^\\d{1,2}\\.?\\d{2}$/; +`, + ); +}; + +await main().catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exit(1); +}); diff --git a/src/_internals/constants/nbs.ts b/src/_internals/constants/nbs.ts new file mode 100644 index 00000000..7390645f --- /dev/null +++ b/src/_internals/constants/nbs.ts @@ -0,0 +1,1207 @@ +/** + * NBS 2.0 (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que Produzam + * Variações no Patrimônio) descriptions, indexed by the raw 9 digit code. + * + * Built from the official `NBSa_2-0.csv` the MDIC publishes on gov.br, a plain + * `NBS 2.0;DESCRIÇÃO` CSV in ISO-8859-1, the version 2.0 as amended by the Portaria Conjunta + * RFB/SCS 2.000 of 18 December 2018. Only the complete codes are kept: the chapter, position and + * subposition headings of the CSV classify nothing by themselves. + * + * Generated by `node ./scripts/nbs.ts`. Do not edit by hand. + * + * @see Official: https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos + * The NBS page of the MDIC, which links the CSV and the Anexo I of the Portaria. + * @see Official: https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/NBSa_2-0.csv + * The NBS 2.0 table in CSV. + */ +export const NBS_DESCRIPTIONS: Record = { + "101011100": "Serviços de construção de edificações residenciais de um e dois pavimentos", + "101011200": "Serviços de construção de edificações residenciais com mais de dois pavimentos", + "101012100": "Serviços de construção de edificações industriais", + "101012200": "Serviços de construção de edificações comerciais", + "101012900": + "Serviços de construção de edificações não residenciais não classificados em subposições anteriores", + "101013000": "Serviços de construção de edificações de uso misto (residencial e não residencial)", + "101021100": + "Serviços de construção de autoestradas (exceto autoestradas elevadas), ruas e estradas", + "101021200": "Serviços de construção de ferrovias", + "101021300": + "Serviços de construção de pistas de pouso e decolagem em aeroportos e de infraestrutura aeroportuária", + "101022000": "Serviços de construção de pontes, autoestradas elevadas e túneis", + "101023100": "Serviços de construção de infraestrutura de proteção e acesso aquaviário", + "101023200": "Serviços de construção de infraestrutura de acostagem aquaviária", + "101023300": + "Serviços de construção de infraestrutura terrestre e de obras de engenharia afins nos portos", + "101023400": "Serviços de construção de barragens", + "101023510": "Serviços de construção de adutoras em conduto livre", + "101023520": "Serviços de construção de sistemas de irrigação", + "101023530": + "Serviços de construção relacionada ao controle dos cursos de água, inclusive canalização", + "101024110": + "Serviços de construção de dutos de longo curso para o transporte de petróleo, seus derivados, e gás", + "101024120": + "Serviços de construção de dutos de longo curso para o transporte e escoamento de águas", + "101024190": + "Serviços de construção de dutos de longo curso não classificados em subposições anteriores", + "101024210": "Serviços de construção de linhas de comunicação de longo curso", + "101024220": "Serviços de construção de linhas de transmissão de alta tensão", + "101025100": "Serviços de construção de dutos locais", + "101025210": "Serviços de construção de linhas locais de comunicação", + "101025220": "Serviços de construção de linhas locais de transmissão de baixa e média tensão", + "101025310": "Serviços de construção de sistemas de esgotos", + "101025320": + "Serviços de construção de sistemas de estações para elevação, tratamento e purificação de água", + "101026100": "Serviços de construção de usinas de geração de energia", + "101026900": + "Serviços de construção de instalações industriais não classificados em subposições anteriores", + "101027000": "Serviços de construção de minas e suas unidades industriais", + "101028000": + "Serviços de construção de instalações para recreação e atividades desportivas ao ar livre", + "101029000": + "Serviços de construção de obras de engenharia civil não classificados em subposições anteriores", + "101031000": "Serviços de demolição", + "101032000": "Serviços de preparação de terrenos e de canteiros de obras", + "101033000": "Serviços de escavação e remoção de terra", + "101034100": "Serviços de perfuração de poços de água", + "101034200": "Serviços de instalação de sistemas sépticos", + "101040000": "Serviços de montagem e de edificação de construções pré-fabricadas", + "101051100": "Serviços de estaqueamento", + "101051200": "Serviços de fundação", + "101052100": "Serviços de construção de estruturas de edificações", + "101052200": "Serviços de construção de estruturas de telhados e coberturas", + "101053000": "Serviços de construção de telhados e coberturas e serviços de impermeabilização", + "101054000": "Serviços de concretagem", + "101055000": "Serviços de montagem de estruturas de aço", + "101056000": "Serviços de alvenaria", + "101057000": "Serviços de andaimes", + "101059000": "Serviços especializados de construção não classificados em subposições anteriores", + "101061100": "Serviços de instalação de fiação elétrica e componentes", + "101061200": "Serviços de instalação de alarmes contra incêndio", + "101061300": "Serviços de instalação de sistemas de alarmes antifurto", + "101061400": "Serviços de instalação de antenas residenciais", + "101061900": "Serviços de instalação elétrica não classificados em subposições anteriores", + "101062100": "Serviços de instalação de tubulação para fornecimento de água", + "101062200": "Serviços de instalação de tubulação para escoamento de água", + "101063100": "Serviços de instalação de equipamentos de aquecimento", + "101063200": "Serviços de instalação de equipamentos de ventilação e de ar condicionado", + "101064000": "Serviços de instalação de gás", + "101065000": "Serviços de instalação de isolamentos", + "101066000": "Serviços de instalação de elevadores, esteiras e escadas rolantes", + "101069000": "Serviços de instalação não classificados em subposições anteriores", + "101071000": "Serviços de vidraçaria", + "101072000": "Serviços de gesso e de estuque", + "101073000": "Serviços de pintura", + "101074000": "Serviços de revestimento de pisos e de paredes", + "101075000": "Serviços de carpintaria e de serralharia", + "101076000": "Serviços de instalação de cercas e grades", + "101079000": "Serviços de acabamento não classificados em subposições anteriores", + "102010000": "Serviços de intermediação na distribuição de mercadorias", + "102020000": "Comércio atacadista", + "102030000": "Comércio varejista", + "102040000": "Serviços de despacho aduaneiro", + "102050000": "Serviços de intermediação na comercialização de energia elétrica", + "103011000": "Fornecimento de refeições acompanhado de serviços de restaurante", + "103012100": "Fornecimento de refeições pelo sistema de autosserviço (self-service)", + "103012200": "Fornecimento de comidas rápidas (fast-food)", + "103012900": + "Fornecimento de refeições com serviços limitados de restaurante não classificado em subposições anteriores", + "103013100": "Fornecimento de alimentação para eventos", + "103013200": + "Fornecimento de alimentação para operadores de transportes (comissaria ou catering)", + "103013900": + "Fornecimento de alimentação, incluindo refeições, sob contrato não classificado em subposições anteriores", + "103019000": "Fornecimento de alimentação não classificado em subposições anteriores", + "103020000": "Fornecimento de bebidas em bares, cervejarias e outros", + "103031100": + "Serviços de hospedagem em quartos ou unidades de hospedagem para visitantes, com serviços diários de faxina", + "103031200": + "Serviços de hospedagem em quartos ou unidades de hospedagem para visitantes, sem serviços diários de faxina", + "103031300": + "Serviços de hospedagem em quartos ou unidades de hospedagem para visitantes, em propriedades partilhadas", + "103031400": + "Serviços de hospedagem em quartos ou unidades de hospedagem para visitantes, em quartos de múltipla ocupação", + "103032000": "Serviços de acampamentos turísticos (camping)", + "103039000": "Serviços de hospedagem para visitantes não classificados em subposições anteriores", + "103041000": + "Serviços de hospedagem em quartos ou unidades de hospedagem para estudantes em residências estudantis", + "103042000": + "Serviços de hospedagem em quartos ou unidades de hospedagem para trabalhadores em hotéis ou campos", + "103049000": + "Serviços de hospedagem, exceto para visitantes não classificados em subposições anteriores", + "104011111": + "Serviços de transporte rodoviário local prestados exclusivamente por meio de ônibus", + "104011119": + "Serviços de transporte rodoviário local regular de passageiros, exceto em áreas metropolitanas não classificados em subitens anteriores", + "104011120": + "Serviços de transporte rodoviário local regular de passageiros, em áreas metropolitanas", + "104011210": "Serviços de transporte escolar", + "104011220": "Serviços de transporte para aeroportos (shuttle)", + "104011290": + "Serviços especiais de transporte rodoviário local regular de passageiros não classificados em itens anteriores", + "104011300": "Serviços de táxi", + "104011400": "Serviços de carro com motorista, exceto táxi", + "104011510": "Serviços de fretamento contínuo, local", + "104011520": "Serviços de fretamento eventual ou turístico, local", + "104011610": "Serviços de transporte ferroviário local de passageiros", + "104011620": "Serviços de transporte metroviário (metrô) local de passageiros", + "104011690": + "Serviços de transporte local de passageiros por veículos sobre trilhos não classificados em itens anteriores", + "104011710": "Serviços de transporte rodoviário para passeios turísticos (sightseeing)", + "104011720": "Serviços de transporte ferroviário para passeios turísticos (sightseeing)", + "104011790": + "Serviços de transporte terrestre para passeios turísticos (sightseeing) não classificados em itens anteriores", + "104011900": + "Serviços de transporte terrestre local de passageiros não classificados em subposições anteriores", + "104012110": + "Serviços de transporte aquaviário local de passageiros, por navegação interior, em embarcações para travessia", + "104012120": + "Serviços de transporte aquaviário local de passageiros, por navegação interior, em embarcações para cruzeiros", + "104012190": + "Serviços de transporte aquaviário local de passageiros, por navegação interior não classificados em itens anteriores", + "104012200": "Serviços de transporte aquaviário local de passageiros por fretamento", + "104012300": "Serviços de transporte aquaviário para passeios turísticos (sightseeing)", + "104012900": + "Serviços de transporte aquaviário local de passageiros não classificados em subposições anteriores", + "104013000": "Serviços de transporte integrado local de passageiros", + "104014100": "Serviços de táxi aéreo local", + "104014200": "Serviços de transporte aéreo local de passageiros por fretamento", + "104014300": "Serviços de transporte aéreo para passeios turísticos (sightseeing)", + "104014900": + "Serviços de transporte aéreo local de passageiros não classificados em subposições anteriores", + "104019000": + "Serviços de transporte local de passageiros não classificados não classificados em subposições anteriores", + "104021110": + "Serviços de transporte rodoviário nacional, exceto local, prestados exclusivamente por meio de ônibus", + "104021190": + "Serviços de transporte rodoviário nacional, exceto local, de passageiros, não classificados não classificados em subitens anteriores", + "104021200": + "Serviços especiais de transporte rodoviário nacional, exceto local, regular de passageiros", + "104021310": "Serviços de fretamento contínuo, nacional, exceto local", + "104021320": "Serviços de fretamento eventual ou turístico, nacional, exceto local", + "104021400": "Serviços de transporte ferroviário nacional, exceto local, de passageiros", + "104021900": + "Serviços de transporte terrestre nacional, exceto local, de passageiros não classificados não classificados em subposições anteriores", + "104022110": + "Serviços de transporte aquaviário de passageiros, por navegação interior, em embarcações para travessia", + "104022120": + "Serviços de transporte aquaviário de passageiros, por navegação interior, em embarcações para cruzeiros", + "104022190": + "Serviços de transporte aquaviário nacional, exceto local, de passageiros, por navegação interior não classificados em itens anteriores", + "104022200": "Serviços de transporte aquaviário nacional costeiro de passageiros", + "104022300": + "Serviços de transporte aquaviário nacional, exceto local, de passageiros por fretamento", + "104022900": + "Serviços de transporte aquaviário nacional, exceto local, de passageiros não classificados em subposições anteriores", + "104023100": "Serviços de transporte aéreo nacional, exceto local, regular de passageiros", + "104023200": "Serviços de táxi aéreo nacional, exceto local", + "104023300": + "Serviços de transporte aéreo nacional, exceto local, de passageiros, por fretamento", + "104023900": + "Serviços de transporte aéreo nacional, exceto local, de passageiros não classificados em subposições anteriores", + "104029000": + "Serviços de transporte nacional, exceto local, de passageiros não classificados em subposições anteriores", + "104031110": "Serviços de transporte de passageiros prestados exclusivamente por meio de ônibus", + "104031190": + "Serviços de transporte rodoviário internacional de passageiros não classificados em itens anteriores", + "104031200": "Serviços de transporte rodoviário internacional de passageiros por fretamento", + "104031310": "Serviços de transporte internacional ferroviário de passageiros", + "104031390": + "Serviços de transporte internacional de passageiros por veículos sobre trilhos não classificados em itens anteriores", + "104031900": + "Serviços de transporte terrestre internacional de passageiros não classificados em subposições anteriores", + "104032110": + "Serviços de transporte aquaviário internacional de passageiros, por navegação interior, em embarcações para travessia", + "104032120": + "Serviços de transporte aquaviário internacional de passageiros, por navegação interior, em embarcações para cruzeiros", + "104032190": + "Serviços de transporte aquaviário internacional de passageiros, por navegação interior não classificados em itens anteriores", + "104032200": "Serviços de transporte aquaviário internacional costeiro de passageiros", + "104032300": "Serviços de transporte aquaviário internacional transoceânico de passageiros", + "104032400": "Serviços de transporte aquaviário internacional de passageiros por fretamento", + "104032900": + "Serviços de transporte aquaviário internacional de passageiros não classificados em subposições anteriores", + "104033100": "Serviços de transporte aéreo internacional regular de passageiros", + "104033200": "Serviços de táxi aéreo internacional", + "104033300": "Serviços de transporte aéreo internacional de passageiros por fretamento", + "104033900": + "Serviços de transporte aéreo internacional de passageiros não classificados em subposições anteriores", + "104039000": + "Serviços de transporte internacional de passageiros não classificados em subposições anteriores", + "104041000": "Locação de veículos rodoviários de passageiros com motorista", + "104042000": "Locação de embarcações de passageiros com tripulação", + "104043000": "Locação de aeronaves de passageiros com tripulação", + "104050000": "Afretamento de embarcações de passageiros por tempo", + "105011110": "Serviços de transporte rodoviário de cargas sólidas a granel", + "105011120": "Serviços de transporte rodoviário de cargas líquidas, ou liquefeitas, a granel", + "105011130": "Serviços de transporte rodoviário de cargas gasosas a granel", + "105011210": "Serviços de transporte rodoviário de carga solta, não unitizada", + "105011220": "Serviços de transporte rodoviário de carga unitizada", + "105011230": "Serviços de transporte rodoviário de carga frigorificada ou climatizada", + "105011310": + "Serviços de transporte rodoviário de cargas em contêineres frigorificados ou climatizados", + "105011320": + "Serviços de transporte rodoviário de cargas em contêineres não frigorificados ou climatizados", + "105011410": "Serviços de transporte rodoviário de cargas vivas", + "105011420": + "Serviços de transporte rodoviário de mudanças domésticas e de mobília e outros objetos de escritório", + "105011430": "Serviços de transporte rodoviário de cargas de grande porte", + "105011440": "Serviços de transporte rodoviário de veículos", + "105011451": + "Serviços de transporte rodoviário de combustíveis, lubrificantes e GLP, inclusive apresentados em botijões metálicos", + "105011452": + "Serviços de transporte rodoviário de produtos químicos perigosos, exceto lubrificantes e GLP", + "105011459": + "Serviços de transporte rodoviário de produtos perigosos não classificados em subitens anteriores", + "105011500": "Serviços de transporte rodoviário de cargas postais e malotes", + "105011900": + "Serviços de transporte rodoviário de cargas não classificados em subposições anteriores", + "105012110": "Serviços de transporte ferroviário de cargas sólidas a granel", + "105012120": "Serviços de transporte ferroviário de cargas líquidas, ou liquefeitas, a granel", + "105012130": "Serviços de transporte ferroviário de cargas gasosas a granel", + "105012210": "Serviços de transporte ferroviário de carga solta, não unitizada", + "105012220": "Serviços de transporte ferroviário de carga unitizada", + "105012230": "Serviços de transporte ferroviário de carga frigorificada ou climatizada", + "105012310": + "Serviços de transporte ferroviário de cargas em contêineres frigorificados ou climatizados", + "105012320": + "Serviços de transporte ferroviário de cargas em contêineres não frigorificados ou climatizados", + "105012410": "Serviços de transporte ferroviário de cargas vivas", + "105012421": + "Serviços de transporte ferroviário de combustíveis, lubrificantes e GLP, inclusive apresentados em botijões metálicos", + "105012422": + "Serviços de transporte ferroviário de produtos químicos perigosos, exceto lubrificantes e GLP", + "105012429": + "Serviços de transporte ferroviário de produtos perigosos não classificados em subposições anteriores", + "105012500": "Serviços de transporte ferroviário de bens e valores", + "105012900": + "Serviços de transporte ferroviário de cargas não classificados em subposições anteriores", + "105013100": "Serviços de transporte de petróleo, gás natural e combustível por meio de dutos", + "105013200": "Serviços de transporte de minérios por meio de dutos", + "105013900": + "Serviços de transporte de cargas por meio de dutos não classificados em subposições anteriores", + "105021110": + "Serviços de transporte aquaviário por navegação interior de cargas sólidas, a granel", + "105021120": + "Serviços de transporte aquaviário por navegação interior de cargas líquidas, ou liquefeitas, a granel", + "105021130": + "Serviços de transporte aquaviário por navegação interior de cargas gasosas a granel", + "105021210": + "Serviços de transporte aquaviário por navegação interior de carga solta, não unitizada", + "105021220": "Serviços de transporte aquaviário por navegação interior de carga unitizada", + "105021230": + "Serviços de transporte aquaviário por navegação interior de carga frigorificada ou climatizada", + "105021310": + "Serviços de transporte aquaviário por navegação interior de cargas em contêineres frigorificados ou climatizados", + "105021320": + "Serviços de transporte aquaviário por navegação interior de cargas em contêineres não frigorificados ou climatizados", + "105021410": "Serviços de transporte aquaviário por navegação interior de cargas vivas", + "105021420": + "Serviços de transporte aquaviário por navegação interior de mudanças domésticas e de mobília e outros objetos de escritório", + "105021430": "Serviços de transporte aquaviário por navegação interior de cargas de grande porte", + "105021440": "Serviços de transporte aquaviário por navegação interior de veículos", + "105021451": + "Serviços de transporte aquaviário por navegação interior de combustíveis, lubrificantes e GLP, inclusive apresentado em botijões metálicos", + "105021452": + "Serviços de transporte aquaviário por navegação interior de produtos químicos perigosos, exceto lubrificantes e GLP", + "105021459": + "Serviços de transporte aquaviário por navegação interior de produtos perigosos não classificados em subposições anteriores", + "105021490": + "Serviços de transporte aquaviário por navegação interior de cargas especiais não classificados em subposições anteriores", + "105021900": + "Serviços de transporte aquaviário por navegação interior de cargas não classificados em subposições anteriores", + "105022110": "Serviços de transporte aquaviário costeiro de cargas sólidas a granel", + "105022120": + "Serviços de transporte aquaviário costeiro de cargas líquidas ou liquefeitas, a granel", + "105022130": "Serviços de transporte aquaviário costeiro de cargas gasosas a granel", + "105022210": "Serviços de transporte aquaviário costeiro de carga solta, não unitizada", + "105022220": "Serviços de transporte aquaviário costeiro de carga unitizada", + "105022230": "Serviços de transporte aquaviário costeiro de carga frigorificada ou climatizada", + "105022310": + "Serviços de transporte aquaviário costeiro de cargas em contêineres frigorificados ou climatizados", + "105022320": + "Serviços de transporte aquaviário costeiro de cargas em contêineres não classificados em subposições anteriores", + "105022410": "Serviços de transporte aquaviário costeiro de cargas vivas", + "105022420": + "Serviços de transporte aquaviário costeiro de mudanças domésticas e de mobília e outros objetos de escritório", + "105022430": "Serviços de transporte aquaviário costeiro de cargas de grande porte", + "105022440": "Serviços de transporte aquaviário costeiro de veículos", + "105022451": + "Serviços de transporte aquaviário costeiro de combustíveis, lubrificantes e GLP, inclusive apresentado em botijões metálicos", + "105022452": + "Serviços de transporte aquaviário costeiro de produtos químicos perigosos, exceto lubrificantes e GLP", + "105022459": + "Serviços de transporte aquaviário costeiro de produtos perigosos não classificados em subposições anteriores", + "105022900": + "Serviços de transportes aquaviário costeiro de cargas não classificados em subposições anteriores", + "105023110": "Serviços de transporte aquaviário transoceânico de cargas sólidas a granel", + "105023120": + "Serviços de transporte aquaviário transoceânico de cargas líquidas, ou liquefeitas, a granel", + "105023130": "Serviços de transporte aquaviário transoceânico de cargas gasosas a granel", + "105023210": "Serviços de transporte aquaviário transoceânico de carga solta, não unitizada", + "105023220": "Serviços de transporte aquaviário transoceânico de carga unitizada", + "105023230": + "Serviços de transporte aquaviário transoceânico de carga frigorificada ou climatizada", + "105023310": + "Serviços de transporte aquaviário transoceânico de cargas em contêineres frigorificados ou climatizados", + "105023320": + "Serviços de transporte aquaviário transoceânico de cargas em contêineres não frigorificados ou climatizados", + "105023410": "Serviços de transporte aquaviário transoceânico de cargas vivas", + "105023420": + "Serviços de transporte aquaviário transoceânico de mudanças domésticas e de mobília e outros objetos de escritório", + "105023430": "Serviços de transporte aquaviário transoceânico de cargas de grande porte", + "105023440": "Serviços de transporte aquaviário transoceânico de veículos", + "105023451": + "Serviços de transporte aquaviário transoceânico de combustíveis, lubrificantes e GLP, inclusive apresentado em botijões metálicos", + "105023452": + "Serviços de transporte aquaviário transoceânico de produtos químicos perigosos, exceto lubrificantes e GLP", + "105023459": + "Serviços de transporte aquaviário transoceânico de produtos perigosos não classificados em subposições anteriores", + "105023900": + "Serviços de transporte aquaviário transoceânico de cargas não classificados em subposições anteriores", + "105031100": + "Serviços de transporte aéreo de cargas em contêineres frigorificados ou climatizados", + "105031200": + "Serviços de transporte aéreo de cargas em contêineres não frigorificados ou climatizados", + "105032100": "Serviços de transporte aéreo de produtos perigosos", + "105032200": "Serviços de transporte aéreo de cargas vivas", + "105032300": "Serviços de transporte aéreo de máquinas e veículos", + "105032400": "Serviços de transporte aéreo de produtos perecíveis", + "105032500": "Serviços de transporte aéreo de cargas frágeis", + "105032600": "Serviços de transporte aéreo de cargas controladas", + "105032700": "Serviços de transporte aéreo de valores", + "105032800": + "Serviços de transporte aéreo de cargas postais, remessas expressas e cargas congêneres", + "105032900": + "Serviços de transporte aéreo de cargas especiais não classificados em subposições anteriores", + "105039000": "Serviços de transporte aéreo de cargas não classificados em subposições anteriores", + "105041100": "Serviços de transporte multimodal de cargas sólidas a granel", + "105041200": "Serviços de transporte multimodal de cargas líquidas, ou liquefeitas, a granel", + "105041300": "Serviços de transporte multimodal de cargas gasosas a granel", + "105042100": "Serviços de transporte multimodal de carga solta, não unitizada", + "105042200": "Serviços de transporte multimodal de carga unitizada", + "105042300": "Serviços de transporte multimodal de carga frigorificada ou climatizada", + "105043100": + "Serviços de transporte multimodal de cargas em contêineres frigorificados ou climatizados", + "105043200": + "Serviços de transporte multimodal de cargas em contêineres não frigorificados ou climatizados", + "105044100": "Serviços de transporte multimodal de cargas vivas", + "105044200": + "Serviços de transporte multimodal de mudanças domésticas e de mobília e outros objetos de escritório", + "105044300": "Serviços de transporte multimodal de cargas de grande porte", + "105044400": "Serviços de transporte multimodal de veículos", + "105044510": + "Serviços de transporte multimodal de combustíveis, lubrificantes e GLP, inclusive apresentado em botijões metálicos", + "105044520": + "Serviços de transporte multimodal de produtos químicos perigosos, exceto lubrificantes e GLP", + "105044590": + "Serviços de transporte multimodal de produtos perigosos não classificados em subposições anteriores", + "105044900": + "Serviços de transporte multimodal de cargas especiais não classificados em subposições anteriores", + "105049000": + "Serviços de transporte multimodal de cargas não classificados em subposições anteriores", + "105051000": "Locação de veículos rodoviários de carga com operador", + "105052000": "Locação de embarcações de carga com tripulação", + "105053000": "Locação de aeronaves de carga com tripulação", + "105060000": "Afretamento de embarcações de carga por tempo", + "106011000": "Serviços de manuseio de contêineres", + "106019000": "Serviços de manuseio de cargas não classificados em subposições anteriores", + "106021000": "Serviços de armazenagem frigorificada", + "106022100": "Serviços de armazenagem de petróleo e seus derivados", + "106022200": + "Serviços de armazenagem de combustíveis, lubrificantes e GLP, inclusive apresentado em botijões metálicos", + "106022300": "Serviços de armazenagem de produtos químicos perigosos", + "106022900": + "Serviços de armazenagem de produtos perigosos não classificados em subposições anteriores", + "106023100": "Serviços de armazenagem de granéis sólidos", + "106023200": "Serviços de armazenagem de granéis líquidos ou liquefeitos", + "106023300": "Serviços de armazenagem de granéis gasosos", + "106029000": "Serviços de armazenagem não classificados em subposições anteriores", + "106030000": "Serviços de apoio ao transporte ferroviário", + "106041000": "Serviços de estações rodoviárias", + "106042100": "Serviços de operação de rodovias", + "106042200": "Serviços de operação de pontes e túneis", + "106043000": "Serviços de estacionamento", + "106044000": "Serviços de reboque para veículos particulares e comerciais", + "106049000": + "Serviços de apoio ao transporte rodoviário não classificados em subposições anteriores", + "106051000": "Serviços de operação de portos e canais, exceto manuseio de cargas", + "106052000": "Serviços de praticagem e de atracação", + "106053000": "Serviços de salvamento de embarcações", + "106054000": "Serviços de navegação de apoio", + "106059000": + "Serviços de apoio ao transporte aquaviário não classificados em subposições anteriores", + "106061100": "Serviços de operação aeroportuária, exceto manuseio de cargas", + "106061200": "Serviços de controle de tráfego aéreo", + "106061900": "Serviços de apoio ao transporte aéreo não classificados em subposições anteriores", + "106062000": "Serviços de apoio ao transporte aeroespacial", + "106070000": "Serviços de agenciamento de transporte de cargas", + "106081000": "Serviços de coleta e entrega de cargas no transporte multimodal", + "106082000": "Serviços de unitização ou desunitização de cargas no transporte multimodal", + "106083000": "Serviços de movimentação de cargas no transporte multimodal", + "106084000": + "Serviços de consolidação ou desconsolidação documental de cargas no transporte multimodal", + "106089000": + "Serviços de apoio ao transporte multimodal de cargas não classificados em subposições anteriores", + "106090000": "Serviços de apoio aos transportes não classificados em posições anteriores", + "107010000": "Serviços postais e de telegrama", + "107020000": + "Serviços de coleta, transporte, remessa ou entrega de documentos ou encomendas, exceto remessas expressas", + "107030000": "Serviços de remessas expressas", + "108011000": "Serviços de transmissão de eletricidade", + "108012000": "Serviços de distribuição de eletricidade", + "108021000": + "Serviços de distribuição de água por meio de tubulações, exceto vapor de água e água quente", + "108022000": + "Serviços de distribuição de vapor de água, água quente e ar condicionado por meio de tubulações", + "108023000": "Serviços de distribuição de água, exceto por meio de tubulações", + "108030000": "Serviços de distribuição de gás canalizado", + "109011000": "Serviços de banco central", + "109012100": "Serviços de depósito para pessoas jurídicas", + "109012200": "Serviços de depósito para pessoas físicas", + "109012900": "Serviços de depósito para outros depositantes", + "109013100": "Serviços de financiamentos imobiliários residenciais", + "109013200": "Serviços de financiamentos imobiliários não residenciais", + "109013300": "Serviços de empréstimos e financiamentos pessoais", + "109013400": "Serviços de empréstimos e financiamentos comerciais", + "109013500": "Serviços de empréstimos e financiamentos industriais", + "109013600": "Serviços de empréstimos e financiamentos agropecuários", + "109013900": "Serviços de concessão de crédito não classificados em subposições anteriores", + "109014000": "Serviços de cartão de crédito", + "109015111": + "Arrendamento mercantil financeiro de veículos rodoviários automotores para o transporte de passageiros", + "109015112": + "Arrendamento mercantil financeiro de veículos rodoviários automotores para o transporte de mercadorias", + "109015113": "Arrendamento mercantil financeiro de veículos e equipamentos ferroviários", + "109015114": + "Arrendamento mercantil financeiro de outros equipamentos de transporte terrestre, inclusive de veículos de uso misto", + "109015115": "Arrendamento mercantil financeiro de navios e outras embarcações", + "109015116": "Arrendamento mercantil financeiro de aeronaves", + "109015117": "Arrendamento mercantil financeiro de contêineres", + "109015121": "Arrendamento mercantil financeiro de máquinas e equipamentos agrícolas", + "109015122": "Arrendamento mercantil financeiro de máquinas e equipamentos de construção", + "109015123": + "Arrendamento mercantil financeiro de máquinas e equipamentos para escritórios, exceto computadores", + "109015124": "Arrendamento mercantil financeiro de computadores", + "109015125": "Arrendamento mercantil financeiro de equipamentos de telecomunicação", + "109015129": + "Arrendamento mercantil financeiro de outras máquinas e equipamentos não classificado em subposições anteriores", + "109015210": + "Arrendamento mercantil financeiro de televisões e outros eletroeletrônicos domésticos, bem como seus acessórios", + "109015220": "Arrendamento mercantil financeiro de mídias gravadas", + "109015230": "Arrendamento mercantil financeiro de móveis e eletrodomésticos", + "109015240": "Arrendamento mercantil financeiro de equipamentos para diversão e lazer", + "109015250": "Arrendamento mercantil financeiro de artigos de cama, mesa e banho", + "109015290": + "Arrendamento mercantil financeiro de outras mercadorias não classificado em subposições anteriores", + "109019000": + "Serviços financeiros, exceto bancos de investimento, serviços de seguros e previdência complementar não classificados em subposições anteriores", + "109021000": "Serviços de valoração de ativos", + "109022000": "Serviços de subscrição de valores mobiliários", + "109023000": "Serviços de fusões e aquisições", + "109024000": "Serviços de capital de risco e finanças corporativas", + "109029000": "Serviços de banco de investimento não classificados em subposições anteriores", + "109031100": "Serviços de seguro de vida", + "109031200": "Serviços de previdência complementar aberta", + "109031300": "Serviços de previdência complementar fechada", + "109032100": "Serviços de seguro saúde", + "109032200": "Serviços de seguro de acidentes", + "109033100": "Serviços de seguro de veículos rodoviários", + "109033200": + "Serviços de seguro de veículos e equipamentos para transporte ferroviário, aquaviário e aéreo", + "109033300": "Serviços de seguro de cargas", + "109033400": "Serviços de seguro de outras propriedades", + "109033500": "Serviços de seguro por responsabilidade civil", + "109033600": "Serviços de seguro de crédito e de caução", + "109033700": "Serviços de seguro de viagem", + "109033800": "Serviços de seguro rural", + "109033900": + "Serviços de outros seguros, excluídos os serviços de resseguro não classificados em subposições anteriores", + "109041000": "Serviços de resseguro de vida", + "109042100": "Serviços de resseguro saúde", + "109042200": "Serviços de resseguro de acidentes", + "109043100": "Serviços de resseguro de veículos rodoviários", + "109043200": + "Serviços de resseguro de veículos e equipamentos para transporte ferroviário, aquaviário e aéreo", + "109043300": "Serviços de resseguro de cargas", + "109043400": "Serviços de resseguro de outras propriedades", + "109043500": "Serviços de resseguro de responsabilidade civil", + "109043600": "Serviços de resseguro de crédito e caução", + "109043700": "Serviços de resseguro rural", + "109043900": "Serviços de outros resseguros não classificados em subposições anteriores", + "109044000": "Serviços de retrocessão", + "109051100": "Serviços de corretagem de títulos", + "109051200": "Serviços de corretagem de derivativos e commodities", + "109051300": + "Serviços de compensação de transações financeiras, inclusive com ativos financeiros (clearinghouse)", + "109052100": "Serviços de gestão e administração de carteiras de ativos, exceto fundos de pensão", + "109052200": "Serviços de administração fundos de investimento e fundos de pensão", + "109052300": "Serviços de gestão e administração de trust", + "109053000": "Serviços de guarda e custódia", + "109054000": "Serviços relacionados à administração de mercados financeiros", + "109055000": "Serviços de consultoria financeira", + "109056000": "Serviços de câmbio", + "109057000": "Serviços de classificação de risco (rating)", + "109058000": "Serviços fiduciários", + "109059000": + "Serviços auxiliares aos serviços financeiros não classificados em subposições anteriores", + "109061100": + "Serviços de agenciamento e corretagem de seguros, resseguros e previdência complementar, exceto de seguros saúde", + "109061200": "Serviços de corretagem de seguros saúde", + "109062000": "Serviços de perícia e avaliação de seguros e resseguros", + "109063000": "Serviços atuariais", + "109064000": "Serviços de gestão de fundos de previdência complementar", + "109069000": + "Serviços auxiliares a seguros, resseguros e previdência complementar não classificados em subposições anteriores", + "109070000": "Serviços de seguro de recebíveis", + "109080000": "Fomento comercial (factoring)", + "109091000": "Serviços de holding de patrimônio de empresas subsidiárias", + "109092000": + "Serviços de holding de valores mobiliários e outros ativos financeiros e de fundos e entidades financeiras similares", + "109101000": "Serviços de planos privados de assistência à saúde", + "109102000": "Serviços de corretagem de planos privados de assistência à saúde", + "109109000": + "Serviços de planos privados de assistência à saúde e serviços relacionados não classificados em subposições anteriores", + "109110000": + "Serviços financeiros e serviços relacionados não classificados em posições anteriores", + "110011100": "Serviços de administração e locação de imóveis residenciais", + "110011210": + "Serviços de administração e locação, sublocação, arrendamento, direito de passagem ou permissão de uso, compartilhado ou não, de ferrovia, rodovia, postes, cabos, dutos e condutos de qualquer natureza", + "110011290": "Serviços de administração e locação de outros imóveis não residenciais", + "110012100": "Serviços de intermediação na compra e venda de imóveis residenciais", + "110012200": "Serviços de intermediação na compra e venda de imóveis não residenciais", + "110013000": "Serviços de avaliação de imóveis", + "110014000": "Serviços de consultoria imobiliária", + "110015000": "Serviços de assessoria de gestão condominial", + "110019000": "Serviços imobiliários não classificados em subposições anteriores", + "110021000": "Locação de imóveis residenciais", + "110022000": "Locação de imóveis não residenciais", + "111011100": + "Arrendamento mercantil operacional ou locação de veículos rodoviários automotores para o transporte de até oito passageiros, sem operador", + "111011200": + "Arrendamento mercantil operacional ou locação de veículos rodoviários automotores para o transporte de cargas, sem operador", + "111011300": + "Arrendamento mercantil operacional ou locação de veículos e equipamentos de transporte ferroviário, sem operador", + "111011400": + "Arrendamento mercantil operacional ou locação de outros equipamentos de transporte terrestre, inclusive de veículos de uso misto, sem operador", + "111011500": + "Arrendamento mercantil operacional ou locação de navios e outras embarcações, sem tripulação", + "111011600": "Arrendamento mercantil operacional ou locação de aeronaves, sem tripulação", + "111011700": "Arrendamento mercantil operacional ou locação de contêineres", + "111012000": + "Arrendamento mercantil operacional ou locação de máquinas e equipamentos agrícolas, sem operador", + "111013000": + "Arrendamento mercantil operacional ou locação de máquinas e equipamentos de construção, sem operador", + "111014000": + "Arrendamento mercantil operacional ou locação de máquinas e equipamentos para escritórios, exceto computadores, sem operador", + "111015000": "Arrendamento mercantil operacional ou locação de computadores, sem operador", + "111016000": + "Arrendamento mercantil operacional ou locação de equipamentos de telecomunicação, sem operador", + "111019000": + "Arrendamento mercantil operacional ou locação de máquinas e equipamentos, sem operador, não classificado em subposições anteriores", + "111021000": + "Arrendamento mercantil operacional ou locação de televisão e outros eletroeletrônicos, bem como seus acessórios", + "111022000": "Arrendamento mercantil operacional ou locação de mídias gravadas", + "111023000": "Arrendamento mercantil operacional ou locação de móveis e eletrodomésticos", + "111024000": + "Arrendamento mercantil operacional ou locação de equipamentos para diversão e lazer", + "111025000": "Arrendamento mercantil operacional ou locação de artigos de cama, mesa e banho", + "111026000": "Arrendamento mercantil operacional ou locação de roupas e calçados", + "111029000": + "Arrendamento mercantil operacional ou locação de outras mercadorias não classificado em subposições anteriores", + "111031000": "Licenciamento de direitos de obras literárias", + "111032100": + "Licenciamento de direitos de produção, distribuição ou comercialização de programas de computador (software)", + "111032200": "Licenciamento de direitos de uso de programas de computador (software)", + "111032300": "Licenciamento de direitos sobre bancos de dados", + "111032900": + "Licenciamento de direitos sobre programas de computador (software) e bancos de dados não classificado em subposições anteriores", + "111033100": "Licenciamento de direitos de autor de obras cinematográficas", + "111033200": "Licenciamento de direitos de autor de obras jornalísticas", + "111033300": "Licenciamento de direitos de autor de obras publicitárias", + "111033400": + "Licenciamento de direitos conexos de artistas intérpretes ou executantes em obras audiovisuais", + "111033500": "Licenciamento de direitos conexos de produtores de obras audiovisuais", + "111033610": + "Licenciamento de direitos de obras audiovisuais sobre transmissões de eventos esportivos", + "111033620": + "Licenciamento de direitos de obras audiovisuais sobre transmissões de programas televisivos", + "111033690": + "Licenciamento de direitos de obras audiovisuais sobre outras transmissões televisivas", + "111033900": + "Licenciamento de direitos de obras audiovisuais não classificado em subposições anteriores", + "111034100": "Licenciamento de direitos de autor de obras musicais ou literomusicais", + "111034200": "Licenciamento de direitos conexos de artistas intérpretes ou executantes", + "111034300": "Licenciamento de direitos conexos de produtores de fonogramas", + "111035000": "Licenciamento de direitos relacionados à radiodifusão", + "111039000": + "Licenciamento de direitos de autor e de direitos conexos não classificado em subposições anteriores", + "111041000": "Licenciamento de direitos sobre patentes", + "111042000": "Licenciamento de direitos sobre marcas", + "111043000": "Licenciamento de direitos sobre desenho industrial", + "111049000": + "Licenciamento de direitos sobre a propriedade industrial não classificado em subposições anteriores", + "111051000": "Licenciamento de direitos sobre cultivares", + "111052000": "Licenciamento de direitos sobre topografias de circuitos integrados", + "111053000": "Licenciamento de direitos relativos à informação não divulgada", + "111054100": "Exploração de recursos vegetais, inclusive florestais", + "111054200": "Exploração de recursos minerais", + "111055100": + "Licenciamento de direitos sobre conhecimento tradicional associado a recursos genéticos", + "111055900": + "Licenciamento de direitos sobre conhecimento tradicional não classificado em subposições anteriores", + "111056000": + "Licenciamento de direitos relativos ao acesso a recursos genéticos, exceto os decorrentes do conhecimento tradicional", + "111057000": + "Licenciamento de direitos sobre informações relativas à experiência adquirida no setor industrial, comercial ou científico (know-how)", + "111059000": "Licenciamento de outros direitos não classificado em subposições anteriores", + "111061000": "Cessão temporária de direitos de obras literárias", + "111062000": "Cessão temporária de direitos sobre programas de computador (software)", + "111063100": "Cessão temporária de direitos de autor de obras cinematográficas", + "111063200": "Cessão temporária de direitos de autor de obras jornalísticas", + "111063300": "Cessão temporária de direitos de autor de obras publicitárias", + "111063400": + "Cessão temporária de direitos conexos de artistas intérpretes ou executantes em obras audiovisuais", + "111063500": "Cessão temporária de direitos conexos de produtores de obras audiovisuais", + "111063610": + "Cessão temporária de direitos de obras audiovisuais sobre transmissões de eventos esportivos", + "111063620": + "Cessão temporária de direitos de obras audiovisuais sobre transmissões de programas televisivos", + "111063690": + "Cessão temporária de direitos de obras audiovisuais sobre outras transmissões televisivas", + "111063900": + "Cessão temporária de direitos de obras audiovisuais não classificada em subposições anteriores", + "111064100": "Cessão temporária de direitos de autor de obras musicais e literomusicais", + "111064200": "Cessão temporária de direitos conexos de artistas intérpretes ou executantes", + "111064300": "Cessão temporária de direitos conexos de produtores de fonogramas", + "111065000": "Cessão temporária de direitos relacionados à radiodifusão", + "111069000": + "Cessão temporária de direitos de autor e de direitos conexos não classificada em subposições anteriores", + "111071000": "Cessão definitiva de direitos de obras literárias", + "111072000": "Cessão definitiva de direitos sobre programas de computador (software)", + "111073100": "Cessão definitiva de direitos de obras cinematográficas", + "111073200": "Cessão definitiva de direitos de obras jornalísticas", + "111073300": "Cessão definitiva de direitos de obras publicitárias", + "111073900": + "Cessão definitiva de direitos de obras audiovisuais não classificada em subposições anteriores", + "111074000": "Cessão definitiva de direitos de obras musicais e fonogramas", + "111075000": "Cessão definitiva de direitos relacionados à radiodifusão", + "111079000": + "Cessão definitiva de direitos de autor e de direitos conexos não classificada em subposições anteriores", + "111081000": "Cessão definitiva de direitos sobre patentes", + "111082000": "Cessão definitiva de direitos sobre marcas", + "111083000": "Cessão definitiva de direitos sobre desenho industrial", + "111089000": + "Cessão definitiva de direitos sobre a propriedade industrial não classificada em subposições anteriores", + "111091000": "Cessão definitiva de direitos sobre cultivares", + "111092000": "Cessão definitiva de direitos sobre topografias de circuitos integrados", + "111093000": "Cessão definitiva de direitos relativos à informação não divulgada", + "111099000": "Cessão definitiva de outros direitos não classificada em subposições anteriores", + "111100000": "Franquia", + "112011100": "Serviços de pesquisa e desenvolvimento em ciências físicas", + "112011200": "Serviços de pesquisa e desenvolvimento em química e biologia", + "112011900": + "Serviços de pesquisa e desenvolvimento em ciências não classificadas em subposições anteriores", + "112012000": "Serviços de pesquisa e desenvolvimento em biotecnologia", + "112013100": + "Serviços de pesquisa e desenvolvimento em Tecnologia da Informação e Comunicação (TIC)", + "112013200": "Serviços de pesquisa e desenvolvimento em nanotecnologia", + "112013300": "Serviços de pesquisa e desenvolvimento em engenharia e tecnologia nucleares", + "112013400": + "Serviços de pesquisa e desenvolvimento em engenharia e tecnologia em micro-ondas de potência", + "112013900": + "Serviços de pesquisa e desenvolvimento em engenharia e tecnologia não classificados em subposições anteriores", + "112014000": + "Serviços de pesquisa e desenvolvimento em ciências médicas, odontológicas e farmacêuticas", + "112015000": "Serviços de pesquisa e desenvolvimento em ciências agrárias", + "112019000": + "Serviços de pesquisa e desenvolvimento em ciências, engenharia e tecnologia não classificados em subposições anteriores", + "112021000": "Serviços de pesquisa e desenvolvimento em psicologia", + "112022000": "Serviços de pesquisa e desenvolvimento em ciências econômicas", + "112023000": "Serviços de pesquisa e desenvolvimento em direito", + "112024000": "Serviços de pesquisa e desenvolvimento em línguas e literatura", + "112029000": + "Serviços de pesquisa e desenvolvimento em ciências sociais e humanidades não classificadas em subposições anteriores", + "112030000": "Serviços de pesquisa e desenvolvimento interdisciplinar", + "113011000": "Serviços de representação e consultoria jurídica criminal", + "113012000": + "Serviços de representação e consultoria jurídica em outras áreas do direito, exceto consultoria tributária", + "113013000": + "Serviços de documentação e certificação, exceto os serviços notariais e de registro", + "113014000": "Serviços de arbitragem, conciliação e mediação", + "113019000": "Serviços jurídicos não classificados em subposições anteriores", + "113021100": "Serviços de auditoria contábil", + "113021900": "Serviços de auditoria não classificados em subposições anteriores", + "113022100": "Serviços de contabilidade", + "113022200": "Serviços de escrituração mercantil", + "113022300": "Serviços de folha de pagamento", + "113031000": "Serviços de consultoria tributária para pessoas jurídicas", + "113032000": "Serviços de consultoria tributária para pessoas físicas", + "113040000": "Serviços notariais e de registro", + "114011100": "Serviços de consultoria em gestão estratégica", + "114011200": "Serviços de consultoria em gestão financeira", + "114011300": "Serviços de consultoria em gestão de recursos humanos", + "114011400": "Serviços de consultoria em gestão de marketing", + "114011500": "Serviços de consultoria em gestão operacional", + "114011600": "Serviços de consultoria em gestão energética", + "114011700": "Serviços de consultoria em gestão de cadeia logística", + "114011800": "Serviços de consultoria em gestão hospitalar", + "114011900": + "Serviços de consultoria em gestão empresarial não classificados em subposições anteriores", + "114012100": "Serviços de gestão em processos de negócios", + "114012200": "Serviços de gestão hospitalar", + "114012900": "Serviços de gestão não classificados em subposições anteriores", + "114013100": "Serviços de assessoria de imprensa", + "114013200": "Serviços de relações públicas", + "114013900": "Serviços de assessoria empresarial não classificados em subposições anteriores", + "114021100": "Serviços de consultoria em arquitetura", + "114021200": "Serviços de arquitetura para projetos de construções residenciais", + "114021300": "Serviços de arquitetura para projetos de construções não residenciais", + "114021400": "Serviços de arquitetura para restauração de prédios históricos", + "114021500": + "Serviços de arquitetura relativos ao acompanhamento e fiscalização da execução de projetos arquitetônicos e urbanísticos", + "114022100": "Serviços de planejamento urbano", + "114022200": "Serviços de planejamento de áreas rurais", + "114023100": "Serviços de consultoria em paisagismo", + "114023200": "Serviços de paisagismo, exceto consultoria", + "114029000": + "Serviços de arquitetura, de planejamento urbano e de áreas rurais e de paisagismo não classificados em subposições anteriores", + "114031000": "Serviços de consultoria em engenharia", + "114032110": "Serviços de engenharia para projetos de construção residencial", + "114032120": "Serviços de engenharia para projetos de construção não residencial", + "114032211": "Serviços de engenharia para projetos de exploração de minerais", + "114032212": "Serviços de engenharia para projetos de exploração de petróleo e gás", + "114032213": "Serviços de engenharia para projetos de refino de petróleo e petroquímica", + "114032214": "Serviços de engenharia para projetos de unidades de produção de biocombustíveis", + "114032221": "Serviços de engenharia para projetos de veículos terrestres", + "114032222": "Serviços de engenharia para projetos de embarcações", + "114032223": "Serviços de engenharia para projetos de veículos aéreos e aeroespaciais", + "114032290": + "Serviços de engenharia para outros projetos industriais e de fabricação, exceto para projetos de energia", + "114032300": "Serviços de engenharia para projetos de infraestrutura de transportes", + "114032400": "Serviços de engenharia para projetos de energia", + "114032500": "Serviços de engenharia para projetos de telecomunicações, radiodifusão e televisão", + "114032600": + "Serviços de engenharia para projetos de gerenciamento de resíduos (perigosos e não perigosos)", + "114032700": "Serviços de engenharia para projetos de distribuição de água e rede de esgoto", + "114032900": "Serviços de engenharia para outros projetos", + "114033000": "Serviços de gerenciamento de projetos de construção", + "114039000": "Serviços de engenharia não classificados em subposições anteriores", + "114041100": "Serviços de consultoria geológica e geofísica", + "114041200": "Serviços geofísicos", + "114041300": "Serviços geoquímicos", + "114041400": "Serviços de informações para avaliação e exploração de recursos naturais", + "114041900": + "Serviços geológicos, geofísicos e outros de prospecção não classificados em subposições anteriores", + "114042100": "Serviços topográficos", + "114042200": "Serviços cartográficos", + "114043000": "Serviços meteorológicos e de previsão do tempo", + "114044100": "Serviços de análise e de exames técnicos sobre pureza e composição", + "114044200": "Serviços de análise e de exames técnicos de propriedades físicas", + "114044300": "Serviços de análise e de exames técnicos de sistemas elétricos e mecânicos", + "114044400": "Serviços de inspeção técnica de veículos de transporte rodoviário", + "114044900": + "Serviços de análise e de exames técnicos não classificados em subposições anteriores", + "114051100": "Serviços hospitalares, com ou sem internação, para animais domésticos", + "114051200": "Serviços de atendimento, assistência ou tratamento para animais domésticos", + "114052100": "Serviços hospitalares, com ou sem internação, para animais de corte", + "114052200": "Serviços de atendimento, assistência ou tratamento para animais de corte", + "114053000": "Serviços funerários, de cremação e de embalsamamento de animais", + "114054000": + "Serviços de bancos de órgãos, sangue, sêmen, tecidos, óvulos e outros materiais biológicos", + "114055000": "Planos de atendimento e assistência médico-veterinária", + "114056000": "Serviços de guarda, adestramento, embelezamento e alojamento", + "114059000": "Serviços veterinários não classificados em subposições anteriores", + "114061100": "Serviços de campanhas publicitárias", + "114061200": "Serviços de marketing direto e mala direta", + "114061900": "Serviços de propaganda não classificados em subposições anteriores", + "114062000": "Aquisição ou venda de espaço ou tempo para propaganda, sob comissão", + "114063100": "Venda de espaço para propaganda em mídia impressa, exceto sob comissão", + "114063200": "Venda de tempo para propaganda em rádio e televisão, exceto sob comissão", + "114063300": + "Venda de espaço para propaganda na rede mundial de computadores, exceto sob comissão", + "114063400": "Venda de espaço para propaganda em mídia exterior, exceto sob comissão", + "114063900": + "Venda de espaço ou tempo para propaganda, exceto sob comissão não classificados em subposições anteriores", + "114070000": "Pesquisas de mercado e serviços de pesquisa de opinião pública", + "114081100": "Serviços fotográficos de retratos", + "114081200": "Serviços fotográficos e videográficos para propaganda", + "114081300": "Serviços fotográficos e videográficos de eventos", + "114081400": "Serviços fotográficos especiais", + "114081500": "Serviços de restauração e retoque de fotografias", + "114081900": "Serviços fotográficos e videográficos não classificados em subposições anteriores", + "114082000": "Serviços de processamento de fotografias", + "114091100": "Serviços de design de interiores para espaços comerciais e públicos", + "114091200": "Serviços de design de interiores para espaços residenciais", + "114092100": + "Serviços de desenho industrial de embalagens, expositores de loja e objetos promocionais para comunicação e vendas", + "114092200": + "Serviços de desenho industrial de produtos, utensílios, equipamentos, vestuário, calçados, ornamentos, joias e objetos pessoais", + "114092300": + "Serviços de desenho industrial de máquinas, equipamentos, acessórios e objetos de uso industrial de qualquer natureza", + "114092400": "Serviços de desenho industrial de mobiliários e itens de decoração", + "114092500": + "Serviços de desenho industrial de utensílios e equipamentos eletrodomésticos e eletroeletrônicos", + "114092900": "Serviços de desenho industrial não classificados em subposições anteriores", + "114093000": "Serviços de design de marcas, imagens, objetos gráficos e digitais", + "114099000": "Serviços especializados de design não classificados em subposições anteriores", + "114101000": "Serviços de consultoria ambiental", + "114109000": + "Serviços de consultoria técnica e científica não classificados em subposições anteriores", + "114110000": "Serviços de tradução e de intérpretes", + "114120000": + "Serviços para registros de marcas comerciais e de franquias empresariais, exceto as licenças de uso de direito", + "114130000": "Serviços de prospecção de clientes", + "114140000": "Serviços de prospecção de fornecedores", + "114150000": + "Serviços profissionais, técnicos e gerenciais não classificados em posições anteriores", + "115011000": "Serviços de consultoria em tecnologia da informação (TI)", + "115012000": "Serviços de segurança em tecnologia da informação (TI)", + "115013000": "Serviços de suporte em tecnologia da informação (TI)", + "115021000": + "Serviços de projeto, desenvolvimento e instalação de aplicativos e programas não personalizados (não customizados)", + "115022000": + "Serviços de projeto e desenvolvimento, adaptação e instalação de aplicativos e programas personalizados (customizados)", + "115023000": + "Serviços de projeto e desenvolvimento de estruturas e conteúdo de páginas eletrônicas", + "115024000": "Serviços de projeto e desenvolvimento de estruturas e conteúdo de bancos de dados", + "115025000": "Serviços de integração de sistemas em tecnologia da informação (TI)", + "115029000": + "Serviços de projeto e desenvolvimento de aplicativos e programas em tecnologia da informação (TI) não classificados em subposições anteriores", + "115030000": "Serviços de projeto e desenvolvimento de redes em tecnologia da informação (TI)", + "115040000": "Serviços de projeto e desenvolvimento de topografias de circuitos integrados", + "115050000": "Serviços de projeto de circuitos integrados", + "115061000": "Serviços de hospedagem de sítios eletrônicos na rede mundial de computadores", + "115062100": "Serviços de hospedagem de aplicativos e programas software como serviço (SaaS)", + "115062200": "Serviços de fornecimento de infraestrutura como serviço (IaaS)", + "115062300": "Serviços de fornecimento de plataformas como serviço (PaaS)", + "115062900": + "Serviços de hospedagem de aplicativos e programas não classificados em subposições anteriores", + "115069000": + "Serviços de hospedagem e de disponibilização de infraestrutura em tecnologia da informação (TI) não classificados em subposições anteriores", + "115071000": "Serviços de gerenciamento de redes em tecnologia da informação (TI)", + "115072000": "Serviços de gerenciamento de sistemas computacionais", + "115079000": + "Serviços de gerenciamento de infraestrutura em tecnologia da informação (TI) não classificados em subposições anteriores", + "115080000": "Serviços de manutenção de aplicativos e programas", + "115090000": "Serviços de processamento de dados", + "115100000": + "Serviços de tecnologia da informação (TI) não classificados em subposições anteriores", + "117011100": "Serviços de interconexão pelo uso da rede fixa", + "117011200": "Serviços de interconexão pelo uso de rede móvel", + "117011900": "Serviços de operadoras não classificados em subposições anteriores", + "117012100": "Serviços de chamadas de telecomunicações fixas comutadas", + "117012900": "Serviços de telecomunicações fixas não classificados em subposições anteriores", + "117013100": "Serviços de voz nas telecomunicações móveis", + "117013200": "Serviços de texto nas telecomunicações móveis", + "117013300": + "Serviços de transmissão de dados nas telecomunicações móveis, exceto serviços de texto", + "117013400": "Serviços de telecomunicações móveis para usuários visitantes (roaming)", + "117014000": "Serviços de redes privadas", + "117015100": "Serviços de transmissão de dados local, nacional ou internacional", + "117015200": "Serviços de exploração de linha dedicada local, nacional ou internacional", + "117019000": + "Serviços de telecomunicações, exceto pela rede mundial de computadores, não classificados em subposições anteriores", + "117021000": + "Serviços de fornecimento de infraestrutura de acesso (backbone) à rede mundial de computadores", + "117022100": "Serviços de acesso à rede mundial de computadores por banda estreita", + "117022200": "Serviços de acesso à rede mundial de computadores por banda larga", + "117029000": + "Serviços de telecomunicações pela rede mundial de computadores não classificados em subposições anteriores", + "117031000": + "Serviços de oferta de livros, jornais, periódicos, diretórios e malas diretas de acesso imediato (on-line)", + "117032100": "Serviços de oferta de áudio para download", + "117032200": "Serviços de oferta de áudio de conteúdo contínuo (streaming)", + "117033100": "Serviços de oferta de arquivos contendo filmes e vídeos para download", + "117033200": "Serviços de oferta de filmes e vídeos de conteúdo contínuo (streaming)", + "117039100": "Serviços de oferta de jogos de acesso imediato (on-line)", + "117039200": "Serviços de oferta de conteúdo de portais de busca na rede mundial de computadores", + "117039900": + "Serviços de oferta de outros conteúdos de acesso imediato (on-line) não classificados em subposições anteriores", + "117041000": "Serviços de agências de notícias para jornais e periódicos", + "117042000": "Serviços de agências de notícias para mídia audiovisual", + "117051000": "Serviços de biblioteca", + "117052000": "Serviços de arquivo", + "117061100": "Serviços de programação dos canais de rádio", + "117061200": "Serviços de programação dos canais de televisão", + "117062100": + "Serviços de transmissão de sinais, sons e imagens de rádio e televisão, aberta ou por assinatura", + "117062200": + "Serviços de distribuição de pacotes básicos de programação de televisão por assinatura", + "117062300": + "Serviços de distribuição de pacotes de programação adicional de televisão por assinatura", + "117062400": + 'Serviços de distribuição de programas de televisão por assinatura, na modalidade "pague por exibição" (pay-per-view)', + "117069000": + "Serviços de difusão, programação e distribuição de programas de rádio e televisão não classificados em subposições anteriores", + "118011100": "Serviço de recrutamento e seleção de profissionais executivos", + "118011200": "Serviço de recrutamento e seleção de profissionais, exceto executivos", + "118012100": "Serviços de fornecimento de mão de obra terceirizada, exceto temporária", + "118012200": "Serviços de fornecimento de mão de obra temporária", + "118012900": + "Serviços de fornecimento de mão de obra não classificados em subposições anteriores", + "118021000": "Serviços de investigação", + "118022000": "Serviços de consultoria em segurança", + "118023000": "Serviços de sistemas de segurança", + "118024000": "Serviços de carro-forte", + "118025000": "Serviços de guarda e escolta armada", + "118029000": "Serviços de segurança não classificados em subposições anteriores", + "118031000": "Serviços gerais de limpeza", + "118032100": "Serviços de desinfecção e extermínio de pragas", + "118032200": "Serviços de limpeza de janelas", + "118032900": "Serviços especializados de limpeza não classificados em subposições anteriores", + "118040000": "Serviços de acondicionamento e empacotamento", + "118051100": "Serviços de reservas para transporte aéreo de passageiros", + "118051200": "Serviços de reservas para transporte ferroviário de passageiros", + "118051300": "Serviços de reservas para transporte rodoviário de passageiros", + "118051400": "Serviços de reservas de carros de aluguel", + "118051900": + "Serviços de reservas para transporte de passageiros não classificados em subposições anteriores", + "118052100": "Serviços de reservas de hospedagem, exceto em unidades compartilhadas", + "118052200": "Serviços de reservas e intercâmbio de unidades compartilhadas (time-share)", + "118052300": "Serviços de reservas em cruzeiros", + "118052400": "Serviços de reservas de pacotes turísticos", + "118053100": "Serviços de reservas para centros de convenções, auditórios e salas de exposições", + "118053200": "Serviços de reservas de ingressos para eventos de entretenimento e recreativos", + "118053900": "Serviços de reservas não classificados em subposições anteriores", + "118054000": "Serviços de operadoras de turismo", + "118055000": "Serviços de guias turísticos", + "118056100": "Serviços de promoção turística", + "118056200": "Serviços de informação a visitantes", + "118061000": "Serviços de informação cadastral e análise de crédito", + "118062000": "Serviços de cobrança", + "118063100": "Serviços de call center", + "118063900": + "Serviços de apoio às atividades empresariais por meio de telefone não classificados em subposições anteriores", + "118064000": "Serviços combinados de escritório e apoio administrativo", + "118065100": "Serviços de fotocópias e outros serviços de reprodução de documentos", + "118065200": "Serviços de execução e envio de mala direta e de elaboração de listas de endereços", + "118065300": "Serviços de preparação de documentos", + "118065900": + "Serviços especializados de apoio a escritório não classificados em subposições anteriores", + "118066100": "Serviços de assistência e organização de convenções", + "118066200": "Serviços de assistência e organização de feiras de negócios", + "118066300": "Serviços de assistência e organização de exposições e outros eventos", + "118067000": "Serviços de jardinagem", + "118068100": "Serviços de agenciamento de modelos", + "118068200": "Serviços de agenciamento de artistas", + "118068300": "Serviços de agenciamento de atletas", + "118069000": "Serviços de apoio não classificados em subposições anteriores", + "119011000": "Serviços de apoio à agricultura", + "119012000": "Serviços de apoio à pecuária", + "119013000": "Serviços de apoio à produção florestal (silvicultura)", + "119014000": "Serviços de apoio à pesca", + "119015000": "Serviços de apoio à aquicultura", + "119021000": "Serviços de apoio à extração de petróleo e gás", + "119029000": "Serviços de apoio à mineração não classificados em subposições anteriores", + "119031100": "Serviços de apoio à transmissão de eletricidade", + "119031200": "Serviços de apoio à distribuição de eletricidade", + "119032000": "Serviços de apoio à distribuição de gás por meio de tubulações", + "119033000": + "Serviços de apoio à distribuição de água por meio de tubulações, exceto vapor de água e água quente", + "119034000": + "Serviços de apoio à distribuição de vapor de água, água quente e ar condicionado por meio de tubulações", + "119035000": "Serviços de apoio à distribuição de água, exceto por meio de tubulações", + "120011000": + "Serviços de manutenção e reparação de produtos metálicos, exceto maquinários e equipamentos", + "120012000": + "Serviços de manutenção e reparação de computadores e seus periféricos e de maquinário para escritório", + "120013110": "Serviços de manutenção e reparação de veículos rodoviários motorizados", + "120013120": "Serviços de manutenção e reparação de veículos rodoviários não motorizados", + "120013200": "Serviços de manutenção e reparação de veículos sobre trilhos", + "120013300": "Serviços de manutenção e reparação de veículos aquaviários", + "120013410": + "Serviços de manutenção e reparação de aeronaves, exceto de motores, turborreatores e turbopropulsores aeronáuticos", + "120013420": + "Serviços de manutenção e reparação de motores, turborreatores e turbopropulsores aeronáuticos", + "120013430": "Serviços de manutenção e reparação de foguetes e equipamentos aeroespaciais", + "120013500": "Serviços de manutenção e reparação de veículos militares", + "120013900": + "Serviços de manutenção e reparação de maquinários e equipamentos de transporte não classificados em subposições anteriores", + "120014000": + "Serviços de manutenção e reparação de plataformas, inclusive navios-plataforma, para extração de petróleo e gás", + "120015000": "Serviços de manutenção e reparação de maquinários e equipamentos de uso industrial", + "120016000": "Serviços de manutenção e reparação de maquinários e equipamentos de uso comercial", + "120017000": "Serviços de manutenção e reparação de equipamentos e aparelhos de telecomunicações", + "120018100": "Serviços de manutenção e reparação de aparelhos eletroeletrônicos domésticos", + "120018200": + "Serviços de manutenção e reparação de instrumentos e equipamentos médico-hospitalares, odontológicos, óticos e de precisão", + "120018300": "Serviços de manutenção e reparação de equipamentos militares", + "120018900": + "Serviços de manutenção e reparação de outros maquinários e equipamentos não classificados em subposições anteriores", + "120021000": "Serviços de manutenção e reparação de produtos de couro, calçados, malas e bolsas", + "120022000": "Serviços de manutenção e reparação de relógios e joias", + "120023000": "Serviços de manutenção e reparação de móveis", + "120024000": "Serviços de manutenção de roupas e outros produtos têxteis", + "120029000": + "Serviços de manutenção e reparação de outros bens de consumo não classificados em subposições anteriores", + "120031000": "Serviços de instalação de produtos metálicos, exceto maquinário e equipamentos", + "120032110": "Serviços de montagem sob encomenda de turbinas industriais", + "120032190": + "Serviços de instalação de maquinários, aparelhos e equipamentos industriais não classificados em itens anteriores", + "120032200": + "Serviços de instalação de computadores e seus periféricos e maquinário de escritório", + "120032300": + "Serviços de instalação de equipamentos e aparelhos de comunicação, incluindo de rádio e de televisão", + "120032400": + "Serviços de instalação de maquinários, equipamentos, instrumentos e aparelhos médico-hospitalares, óticos e de precisão", + "120032510": "Serviços de instalação de sensores e sistemas de armas", + "120032520": "Serviços de instalação de maquinários, aparelhos e equipamentos de emprego militar", + "120032610": + "Serviços de montagem sob encomenda de motores, turborreatores e turbopropulsores aeronáuticos", + "120032690": + "Serviços de instalação de maquinários e equipamentos de transporte não classificados em itens anteriores", + "120032900": + "Serviços de instalação de maquinários, aparelhos e equipamentos não classificados em subposições anteriores", + "121011000": "Serviços de editoração", + "121012100": "Serviços de impressão", + "121012200": "Serviços relacionados à impressão", + "121012300": "Serviços de reprodução de mídia gravada", + "121013000": "Serviços de publicação", + "122011100": "Serviços de creche ou entidade equivalente", + "122011200": "Serviços de pré-escola", + "122011900": "Serviços de educação infantil não classificados em subposições anteriores", + "122012000": "Serviços de ensino fundamental", + "122013000": "Serviços de ensino médio", + "122020000": "Serviços de educação técnica de nível médio", + "122031000": "Serviços de ensino fundamental de jovens e adultos", + "122032000": "Serviços de ensino médio de jovens e adultos", + "122041000": "Serviços educacionais de graduação", + "122042000": "Serviços educacionais de pós-graduação", + "122043000": "Serviços educacionais de extensão", + "122044000": "Serviços educacionais de cursos sequenciais", + "122051100": "Serviços de educação com enfoque cultural", + "122051200": "Serviços de educação desportiva e recreacional", + "122051300": "Serviços de educação em línguas estrangeiras e de sinais", + "122051400": "Serviços de palestras e conferências", + "122051900": + "Serviços de educação, inclusive treinamento não classificados em subposições anteriores", + "122052000": "Serviços de apoio aos serviços educacionais", + "123011100": "Serviços cirúrgicos", + "123011200": "Serviços ginecológicos e obstétricos", + "123011300": "Serviços psiquiátricos", + "123011400": "Serviços prestados em Unidades de Terapia Intensiva", + "123011500": "Serviços de atendimento de urgência", + "123011900": "Serviços hospitalares não classificados em subposições anteriores", + "123012100": "Serviços de clínica médica", + "123012200": "Serviços médicos especializados", + "123012300": "Serviços odontológicos", + "123019100": "Serviços de enfermagem", + "123019200": "Serviços de fisioterapia", + "123019300": "Serviços laboratoriais", + "123019400": "Serviços de diagnóstico por imagem", + "123019500": "Serviços de bancos de material biológico humano", + "123019600": "Serviços de ambulância", + "123019700": "Serviços de assistência ao parto e pós-parto", + "123019800": "Serviços de psicologia", + "123019900": "Outros serviços de saúde humana não classificados em subposições anteriores", + "123021000": "Serviços de cuidado em saúde em unidades de acolhimento", + "123022100": "Serviços de assistência a idosos em unidades de acolhimento", + "123022200": + "Serviços de assistência a crianças e adolescentes com deficiência em unidades de acolhimento", + "123022300": "Serviços de assistência a adultos com deficiência em unidades de acolhimento", + "123030000": "Serviços de assistência social com acomodação", + "123041100": "Serviços de reabilitação vocacional para pessoas com deficiência", + "123041200": "Serviços de reabilitação vocacional para desempregados", + "123041900": "Serviço de reabilitação vocacional não classificados nas subposições anteriores", + "123042000": "Serviços de orientação e aconselhamento relacionados a crianças e adolescentes", + "123049000": + "Serviços de assistência social sem acomodação não classificados em subposições anteriores", + "124010000": "Serviços de tratamento de água", + "124021000": "Serviços de esgoto e tratamento de esgotos", + "124022000": "Serviços de esvaziamento e limpeza de fossas sépticas", + "124031100": "Serviços de coleta de resíduos de serviços de saúde e outros resíduos biológicos", + "124031200": + "Serviços de coleta de resíduos perigosos industriais, exceto resíduos de serviços de saúde e outros resíduos biológicos", + "124031900": + "Serviços de coleta de outros resíduos perigosos não classificados em subposições anteriores", + "124032100": "Serviços de coleta de resíduos recicláveis, não perigosos, de origem doméstica", + "124032200": + "Serviços de coleta de resíduos recicláveis, não perigosos, exceto de origem doméstica", + "124033100": "Serviços de coleta de resíduos gerais de origem doméstica", + "124033200": "Serviços de coleta de resíduos gerais, exceto de origem doméstica", + "124041100": "Serviços de triagem, preparação, consolidação e estocagem de resíduos perigosos", + "124041200": "Serviços de demolição e desmantelamento de embarcações, veículos e outros bens", + "124041300": + "Serviços de triagem, preparação, consolidação e estocagem de resíduos recicláveis não perigosos", + "124041900": + "Serviços de triagem, preparação, consolidação e estocagem de resíduos não perigosos, exceto os recicláveis", + "124042100": "Serviços de tratamento de resíduos perigosos", + "124042200": "Serviços de eliminação de resíduos perigosos", + "124043100": + "Serviços de tratamento e eliminação de resíduos não perigosos em aterros sanitários", + "124043200": + "Serviços de tratamento e eliminação de resíduos não perigosos em aterros, exceto os sanitários", + "124043300": "Serviços de incineração de resíduos não perigosos", + "124043900": + "Serviços de tratamento e eliminação de resíduos não perigosos não classificados em subposições anteriores", + "124051100": "Serviços de remediação e limpeza do ar", + "124051200": "Serviços de remediação e limpeza de águas de superfície", + "124051300": "Serviços de remediação e limpeza do solo e de águas subterrâneas", + "124051400": "Serviços de remediação em edificações", + "124052000": "Serviços de contenção, controle e monitoramento de áreas contaminadas", + "124059000": "Serviços de remediação não classificados em subposições anteriores", + "124061000": "Serviços de varrição de vias e áreas públicas", + "124069000": "Serviços de limpeza urbana e similares não classificados em subposições anteriores", + "124070000": "Serviços de proteção ambiental não classificados em posições anteriores", + "125011100": "Serviços de gravação de som em estúdio", + "125011200": "Serviços de gravação de som ao vivo", + "125012100": "Serviços de produção de programas de televisão, videoteipes e filmes", + "125012200": "Serviços de produção de programas de rádio", + "125013100": "Serviços de edição de obras audiovisuais", + "125013200": "Serviços de duplicação e transferência de obras audiovisuais", + "125013300": "Serviços de correção de cor e restauração digital de obras audiovisuais", + "125013400": "Serviços de efeitos visuais em obras audiovisuais", + "125013500": "Serviços de animação", + "125013600": "Serviços de legendas, títulos e dublagem em obras audiovisuais", + "125013700": "Serviços de projeto e edição de som em obras audiovisuais", + "125013900": + "Serviços de pós-produção de obras audiovisuais não classificados em subposições anteriores", + "125014000": "Serviços de agenciamento para a comercialização de obras audiovisuais", + "125015000": "Serviços de projeção de filmes", + "125019000": + "Serviços de produção audiovisual, de apoio e relacionados não classificados em subposições anteriores", + "125021000": "Serviços de organização e promoção de atuações artísticas ao vivo", + "125022000": "Serviços de produção e apresentação de atuações artísticas ao vivo", + "125023000": "Serviços de apoio para atuações artísticas ao vivo", + "125029000": + "Serviços de apresentação e promoção de atuações artísticas e outros serviços de entretenimento ao vivo não classificados em subposições anteriores", + "125031000": "Serviços de atuação artística", + "125032000": + "Serviços de autores, compositores, escultores, pintores e outros artistas, exceto os de atuação artística", + "125041100": "Serviços de museus", + "125041200": "Serviços de preservação e operação de locais e construções históricas", + "125042100": "Serviços de jardins botânico e zoológico", + "125042200": "Serviços de reserva natural, incluindo preservação de vida selvagem", + "125051000": + "Serviços de organização e promoção de eventos desportivos e recreacionais desportivos", + "125052000": "Serviços de clubes desportivos", + "125059000": + "Serviços desportivos e recreacionais desportivos não classificados em subposições anteriores", + "125060000": + "Serviços fornecidos por atletas e desportistas, por conta própria, e serviços de apoio relacionados com desportes e recreação desportiva", + "125071000": "Serviços de parques temáticos de diversão", + "125079000": + "Serviços de parques de diversão e atrações similares não classificados em subposições anteriores", + "125080000": + "Serviços recreativos, culturais e desportivos não classificados em posições anteriores", + "126011000": "Serviços de limpeza de têxteis, exceto quando realizados a seco", + "126012000": "Serviços de limpeza a seco", + "126013000": "Serviços de tinturaria", + "126014000": "Serviços de passadoria de roupas e outros artigos têxteis", + "126019000": "Serviços de lavanderia não classificados em subposições anteriores", + "126021000": "Serviços de cabeleireiros e barbeiros", + "126022000": "Serviços de manicure, pedicure e tratamento cosmético", + "126023000": "Serviços de bem-estar físico", + "126029000": + "Serviços de tratamento de beleza e bem-estar físico não classificados em subposições anteriores", + "126030000": "Serviços funerários, de cremação e de embalsamamento", + "126040000": "Serviços de confecção de roupas e outros artigos têxteis", + "126050000": "Serviços domésticos", + "126060000": "Serviços pessoais não classificados em posições anteriores", +}; + +/** + * Shape an NBS code has to be written in: the 9 digits, optionally split into the printed + * groups of 1, 4, 2 and 2 by a single whitespace or mask character. + */ +export const NBS_FORMAT_REGEX = /^\d[\s.\-/]?\d{4}[\s.\-/]?\d{2}[\s.\-/]?\d{2}$/; diff --git a/src/_internals/constants/service-items.ts b/src/_internals/constants/service-items.ts new file mode 100644 index 00000000..d4c0d861 --- /dev/null +++ b/src/_internals/constants/service-items.ts @@ -0,0 +1,315 @@ +/** + * The subitems in force of the service list annexed to the Lei Complementar 116/2003, indexed by + * the raw 4 digits of the subitem (`0101` for `1.01`), the first four digits of the national + * `cTribNac` code. + * + * Built from the sheet `LISTA.SERV.NAC.` of the `ANEXO_B-NBS2-LISTA_SERVICO_NACIONAL` workbook + * of the Sistema Nacional NFS-e, which prints the list in force, vetoed subitems left out and + * the amendments of later leis complementares applied. The item headings, the national codes a + * subitem is split into and item 99, an addition of the national list, are not part of the law + * and are left out. + * + * Generated by `node ./scripts/service-items.ts` from `anexo_b-nbs2-lista_servico_nacional-snnfse-v1-01-20260122.xlsx`. + * Do not edit by hand. + * + * @see Official: https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm + * Lei Complementar 116/2003, "Lista de serviços anexa". + * @see Official: https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual + * Sistema Nacional NFS-e, current technical documentation, ANEXO B. + */ +export const SERVICE_ITEM_DESCRIPTIONS: Record = { + "0101": "Análise e desenvolvimento de sistemas.", + "0102": "Programação.", + "0103": + "Processamento, armazenamento ou hospedagem de dados, textos, imagens, vídeos, páginas eletrônicas, aplicativos e sistemas de informação, entre outros formatos, e congêneres.", + "0104": + "Elaboração de programas de computadores, inclusive de jogos eletrônicos, independentemente da arquitetura construtiva da máquina em que o programa será executado, incluindo tablets, smartphones e congêneres.", + "0105": "Licenciamento ou cessão de direito de uso de programas de computação.", + "0106": "Assessoria e consultoria em informática.", + "0107": + "Suporte técnico em informática, inclusive instalação, configuração e manutenção de programas de computação e bancos de dados.", + "0108": "Planejamento, confecção, manutenção e atualização de páginas eletrônicas.", + "0109": + "Disponibilização, sem cessão definitiva, de conteúdos de áudio, vídeo, imagem e texto por meio da internet, respeitada a imunidade de livros, jornais e periódicos (exceto a distribuição de conteúdos pelas prestadoras de Serviço de Acesso Condicionado, de que trata a Lei nº 12.485, de 12 de setembro de 2011, sujeita ao ICMS).", + "0201": "Serviços de pesquisas e desenvolvimento de qualquer natureza.", + "0302": "Cessão de direito de uso de marcas e de sinais de propaganda.", + "0303": + "Exploração de salões de festas, centro de convenções, escritórios virtuais, stands, quadras esportivas, estádios, ginásios, auditórios, casas de espetáculos, parques de diversões, canchas e congêneres, para realização de eventos ou negócios de qualquer natureza.", + "0304": + "Locação, sublocação, arrendamento, direito de passagem ou permissão de uso, compartilhado ou não, de ferrovia, rodovia, postes, cabos, dutos e condutos de qualquer natureza.", + "0305": "Cessão de andaimes, palcos, coberturas e outras estruturas de uso temporário.", + "0401": "Medicina e biomedicina.", + "0402": + "Análises clínicas, patologia, eletricidade médica, radioterapia, quimioterapia, ultra-sonografia, ressonância magnética, radiologia, tomografia e congêneres.", + "0403": + "Hospitais, clínicas, laboratórios, sanatórios, manicômios, casas de saúde, prontos-socorros, ambulatórios e congêneres.", + "0404": "Instrumentação cirúrgica.", + "0405": "Acupuntura.", + "0406": "Enfermagem, inclusive serviços auxiliares.", + "0407": "Serviços farmacêuticos.", + "0408": "Terapia ocupacional, fisioterapia e fonoaudiologia.", + "0409": "Terapias de qualquer espécie destinadas ao tratamento físico, orgânico e mental.", + "0410": "Nutrição.", + "0411": "Obstetrícia.", + "0412": "Odontologia.", + "0413": "Ortóptica.", + "0414": "Próteses sob encomenda.", + "0415": "Psicanálise.", + "0416": "Psicologia.", + "0417": "Casas de repouso e de recuperação, creches, asilos e congêneres.", + "0418": "Inseminação artificial, fertilização in vitro e congêneres.", + "0419": "Bancos de sangue, leite, pele, olhos, óvulos, sêmen e congêneres.", + "0420": + "Coleta de sangue, leite, tecidos, sêmen, órgãos e materiais biológicos de qualquer espécie.", + "0421": "Unidade de atendimento, assistência ou tratamento móvel e congêneres.", + "0422": + "Planos de medicina de grupo ou individual e convênios para prestação de assistência médica, hospitalar, odontológica e congêneres.", + "0423": + "Outros planos de saúde que se cumpram através de serviços de terceiros contratados, credenciados, cooperados ou apenas pagos pelo operador do plano mediante indicação do beneficiário.", + "0501": "Medicina veterinária e zootecnia.", + "0502": "Hospitais, clínicas, ambulatórios, prontos-socorros e congêneres, na área veterinária.", + "0503": "Laboratórios de análise na área veterinária.", + "0504": "Inseminação artificial, fertilização in vitro e congêneres.", + "0505": "Bancos de sangue e de órgãos e congêneres.", + "0506": + "Coleta de sangue, leite, tecidos, sêmen, órgãos e materiais biológicos de qualquer espécie.", + "0507": "Unidade de atendimento, assistência ou tratamento móvel e congêneres.", + "0508": "Guarda, tratamento, amestramento, embelezamento, alojamento e congêneres.", + "0509": "Planos de atendimento e assistência médico-veterinária.", + "0601": "Barbearia, cabeleireiros, manicuros, pedicuros e congêneres.", + "0602": "Esteticistas, tratamento de pele, depilação e congêneres.", + "0603": "Banhos, duchas, sauna, massagens e congêneres.", + "0604": "Ginástica, dança, esportes, natação, artes marciais e demais atividades físicas.", + "0605": "Centros de emagrecimento, spa e congêneres.", + "0606": "Aplicação de tatuagens, piercings e congêneres.", + "0701": + "Engenharia, agronomia, agrimensura, arquitetura, geologia, urbanismo, paisagismo e congêneres.", + "0702": + "Execução, por administração, empreitada ou subempreitada, de obras de construção civil, hidráulica ou elétrica e de outras obras semelhantes, inclusive sondagem, perfuração de poços, escavação, drenagem e irrigação, terraplanagem, pavimentação, concretagem e a instalação e montagem de produtos, peças e equipamentos (exceto o fornecimento de mercadorias produzidas pelo prestador de serviços fora do local da prestação dos serviços, que fica sujeito ao ICMS).", + "0703": + "Elaboração de planos diretores, estudos de viabilidade, estudos organizacionais e outros, relacionados com obras e serviços de engenharia; elaboração de anteprojetos, projetos básicos e projetos executivos para trabalhos de engenharia.", + "0704": "Demolição.", + "0705": + "Reparação, conservação e reforma de edifícios, estradas, pontes, portos e congêneres (exceto o fornecimento de mercadorias produzidas pelo prestador dos serviços, fora do local da prestação dos serviços, que fica sujeito ao ICMS).", + "0706": + "Colocação e instalação de tapetes, carpetes, assoalhos, cortinas, revestimentos de parede, vidros, divisórias, placas de gesso e congêneres, com material fornecido pelo tomador do serviço.", + "0707": "Recuperação, raspagem, polimento e lustração de pisos e congêneres.", + "0708": "Calafetação.", + "0709": + "Varrição, coleta, remoção, incineração, tratamento, reciclagem, separação e destinação final de lixo, rejeitos e outros resíduos quaisquer.", + "0710": + "Limpeza, manutenção e conservação de vias e logradouros públicos, imóveis, chaminés, piscinas, parques, jardins e congêneres.", + "0711": "Decoração e jardinagem, inclusive corte e poda de árvores.", + "0712": + "Controle e tratamento de efluentes de qualquer natureza e de agentes físicos, químicos e biológicos.", + "0713": + "Dedetização, desinfecção, desinsetização, imunização, higienização, desratização, pulverização e congêneres.", + "0716": + "Florestamento, reflorestamento, semeadura, adubação, reparação de solo, plantio, silagem, colheita, corte e descascamento de árvores, silvicultura, exploração florestal e dos serviços congêneres indissociáveis da formação, manutenção e colheita de florestas, para quaisquer fins e por quaisquer meios.", + "0717": "Escoramento, contenção de encostas e serviços congêneres.", + "0718": + "Limpeza e dragagem de rios, portos, canais, baías, lagos, lagoas, represas, açudes e congêneres.", + "0719": + "Acompanhamento e fiscalização da execução de obras de engenharia, arquitetura e urbanismo.", + "0720": + "Aerofotogrametria (inclusive interpretação), cartografia, mapeamento, levantamentos topográficos, batimétricos, geográficos, geodésicos, geológicos, geofísicos e congêneres.", + "0721": + "Pesquisa, perfuração, cimentação, mergulho, perfilagem, concretação, testemunhagem, pescaria, estimulação e outros serviços relacionados com a exploração e explotação de petróleo, gás natural e de outros recursos minerais.", + "0722": "Nucleação e bombardeamento de nuvens e congêneres.", + "0801": "Ensino regular pré-escolar, fundamental, médio e superior.", + "0802": + "Instrução, treinamento, orientação pedagógica e educacional, avaliação de conhecimentos de qualquer natureza.", + "0901": + "Hospedagem de qualquer natureza em hotéis, apart-service condominiais, flat, apart-hotéis, hotéis residência, residence-service, suite service, hotelaria marítima, motéis, pensões e congêneres; ocupação por temporada com fornecimento de serviço (o valor da alimentação e gorjeta, quando incluído no preço da diária, fica sujeito ao Imposto Sobre Serviços).", + "0902": + "Agenciamento, organização, promoção, intermediação e execução de programas de turismo, passeios, viagens, excursões, hospedagens e congêneres.", + "0903": "Guias de turismo.", + "1001": + "Agenciamento, corretagem ou intermediação de câmbio, de seguros, de cartões de crédito, de planos de saúde e de planos de previdência privada.", + "1002": + "Agenciamento, corretagem ou intermediação de títulos em geral, valores mobiliários e contratos quaisquer.", + "1003": + "Agenciamento, corretagem ou intermediação de direitos de propriedade industrial, artística ou literária.", + "1004": + "Agenciamento, corretagem ou intermediação de contratos de arrendamento mercantil (leasing), de franquia (franchising) e de faturização (factoring).", + "1005": + "Agenciamento, corretagem ou intermediação de bens móveis ou imóveis, não abrangidos em outros itens ou subitens, inclusive aqueles realizados no âmbito de Bolsas de Mercadorias e Futuros, por quaisquer meios.", + "1006": "Agenciamento marítimo.", + "1007": "Agenciamento de notícias.", + "1008": + "Agenciamento de publicidade e propaganda, inclusive o agenciamento de veiculação por quaisquer meios.", + "1009": "Representação de qualquer natureza, inclusive comercial.", + "1010": "Distribuição de bens de terceiros.", + "1101": + "Guarda e estacionamento de veículos terrestres automotores, de aeronaves e de embarcações.", + "1102": "Vigilância, segurança ou monitoramento de bens, pessoas e semoventes.", + "1103": "Escolta, inclusive de veículos e cargas.", + "1104": + "Armazenamento, depósito, carga, descarga, arrumação e guarda de bens de qualquer espécie.", + "1105": + "Serviços relacionados ao monitoramento e rastreamento a distância, em qualquer via ou local, de veículos, cargas, pessoas e semoventes em circulação ou movimento, realizados por meio de telefonia móvel, transmissão de satélites, rádio ou qualquer outro meio, inclusive pelas empresas de Tecnologia da Informação Veicular, independentemente de o prestador de serviços ser proprietário ou não da infraestrutura de telecomunicações que utiliza.", + "1201": "Espetáculos teatrais.", + "1202": "Exibições cinematográficas.", + "1203": "Espetáculos circenses.", + "1204": "Programas de auditório.", + "1205": "Parques de diversões, centros de lazer e congêneres.", + "1206": "Boates, taxi-dancing e congêneres.", + "1207": + "Shows, ballet, danças, desfiles, bailes, óperas, concertos, recitais, festivais e congêneres.", + "1208": "Feiras, exposições, congressos e congêneres.", + "1209": "Bilhares, boliches e diversões eletrônicas ou não.", + "1210": "Corridas e competições de animais.", + "1211": + "Competições esportivas ou de destreza física ou intelectual, com ou sem a participação do espectador.", + "1212": "Execução de música.", + "1213": + "Produção, mediante ou sem encomenda prévia, de eventos, espetáculos, entrevistas, shows, ballet, danças, desfiles, bailes, teatros, óperas, concertos, recitais, festivais e congêneres.", + "1214": + "Fornecimento de música para ambientes fechados ou não, mediante transmissão por qualquer processo.", + "1215": "Desfiles de blocos carnavalescos ou folclóricos, trios elétricos e congêneres.", + "1216": + "Exibição de filmes, entrevistas, musicais, espetáculos, shows, concertos, desfiles, óperas, competições esportivas, de destreza intelectual ou congêneres.", + "1217": "Recreação e animação, inclusive em festas e eventos de qualquer natureza.", + "1302": "Fonografia ou gravação de sons, inclusive trucagem, dublagem, mixagem e congêneres.", + "1303": + "Fotografia e cinematografia, inclusive revelação, ampliação, cópia, reprodução, trucagem e congêneres.", + "1304": "Reprografia, microfilmagem e digitalização.", + "1305": + "Composição gráfica, inclusive confecção de impressos gráficos, fotocomposição, clicheria, zincografia, litografia e fotolitografia, exceto se destinados a posterior operação de comercialização ou industrialização, ainda que incorporados, de qualquer forma, a outra mercadoria que deva ser objeto de posterior circulação, tais como bulas, rótulos, etiquetas, caixas, cartuchos, embalagens e manuais técnicos e de instrução, quando ficarão sujeitos ao ICMS.", + "1401": + "Lubrificação, limpeza, lustração, revisão, carga e recarga, conserto, restauração, blindagem, manutenção e conservação de máquinas, veículos, aparelhos, equipamentos, motores, elevadores ou de qualquer objeto (exceto peças e partes empregadas, que ficam sujeitas ao ICMS).", + "1402": "Assistência técnica.", + "1403": + "Recondicionamento de motores (exceto peças e partes empregadas, que ficam sujeitas ao ICMS).", + "1404": "Recauchutagem ou regeneração de pneus.", + "1405": + "Restauração, recondicionamento, acondicionamento, pintura, beneficiamento, lavagem, secagem, tingimento, galvanoplastia, anodização, corte, recorte, plastificação, costura, acabamento, polimento e congêneres de objetos quaisquer.", + "1406": + "Instalação e montagem de aparelhos, máquinas e equipamentos, inclusive montagem industrial, prestados ao usuário final, exclusivamente com material por ele fornecido.", + "1407": "Colocação de molduras e congêneres.", + "1408": "Encadernação, gravação e douração de livros, revistas e congêneres.", + "1409": + "Alfaiataria e costura, quando o material for fornecido pelo usuário final, exceto aviamento.", + "1410": "Tinturaria e lavanderia.", + "1411": "Tapeçaria e reforma de estofamentos em geral.", + "1412": "Funilaria e lanternagem.", + "1413": "Carpintaria e serralheria.", + "1414": "Guincho intramunicipal, guindaste e içamento.", + "1501": + "Administração de fundos quaisquer, de consórcio, de cartão de crédito ou débito e congêneres, de carteira de clientes, de cheques pré-datados e congêneres.", + "1502": + "Abertura de contas em geral, inclusive conta-corrente, conta de investimentos e aplicação e caderneta de poupança, no País e no exterior, bem como a manutenção das referidas contas ativas e inativas.", + "1503": + "Locação e manutenção de cofres particulares, de terminais eletrônicos, de terminais de atendimento e de bens e equipamentos em geral.", + "1504": + "Fornecimento ou emissão de atestados em geral, inclusive atestado de idoneidade, atestado de capacidade financeira e congêneres.", + "1505": + "Cadastro, elaboração de ficha cadastral, renovação cadastral e congêneres, inclusão ou exclusão no Cadastro de Emitentes de Cheques sem Fundos - CCF ou em quaisquer outros bancos cadastrais.", + "1506": + "Emissão, reemissão e fornecimento de avisos, comprovantes e documentos em geral; abono de firmas; coleta e entrega de documentos, bens e valores; comunicação com outra agência ou com a administração central; licenciamento eletrônico de veículos; transferência de veículos; agenciamento fiduciário ou depositário; devolução de bens em custódia.", + "1507": + "Acesso, movimentação, atendimento e consulta a contas em geral, por qualquer meio ou processo, inclusive por telefone, fac-símile, internet e telex, acesso a terminais de atendimento, inclusive vinte e quatro horas; acesso a outro banco e à rede compartilhada; fornecimento de saldo, extrato e demais informações relativas a contas em geral, por qualquer meio ou processo.", + "1508": + "Emissão, reemissão, alteração, cessão, substituição, cancelamento e registro de contrato de crédito; estudo, análise e avaliação de operações de crédito; emissão, concessão, alteração ou contratação de aval, fiança, anuência e congêneres; serviços relativos à abertura de crédito, para quaisquer fins.", + "1509": + "Arrendamento mercantil (leasing) de quaisquer bens, inclusive cessão de direitos e obrigações, substituição de garantia, alteração, cancelamento e registro de contrato, e demais serviços relacionados ao arrendamento mercantil (leasing).", + "1510": + "Serviços relacionados a cobranças, recebimentos ou pagamentos em geral, de títulos quaisquer, de contas ou carnês, de câmbio, de tributos e por conta de terceiros, inclusive os efetuados por meio eletrônico, automático ou por máquinas de atendimento; fornecimento de posição de cobrança, recebimento ou pagamento; emissão de carnês, fichas de compensação, impressos e documentos em geral.", + "1511": + "Devolução de títulos, protesto de títulos, sustação de protesto, manutenção de títulos, reapresentação de títulos, e demais serviços a eles relacionados.", + "1512": "Custódia em geral, inclusive de títulos e valores mobiliários.", + "1513": + "Serviços relacionados a operações de câmbio em geral, edição, alteração, prorrogação, cancelamento e baixa de contrato de câmbio; emissão de registro de exportação ou de crédito; cobrança ou depósito no exterior; emissão, fornecimento e cancelamento de cheques de viagem; fornecimento, transferência, cancelamento e demais serviços relativos a carta de crédito de importação, exportação e garantias recebidas; envio e recebimento de mensagens em geral relacionadas a operações de câmbio.", + "1514": + "Fornecimento, emissão, reemissão, renovação e manutenção de cartão magnético, cartão de crédito, cartão de débito, cartão salário e congêneres.", + "1515": + "Compensação de cheques e títulos quaisquer; serviços relacionados a depósito, inclusive depósito identificado, a saque de contas quaisquer, por qualquer meio ou processo, inclusive em terminais eletrônicos e de atendimento.", + "1516": + "Emissão, reemissão, liquidação, alteração, cancelamento e baixa de ordens de pagamento, ordens de crédito e similares, por qualquer meio ou processo; serviços relacionados à transferência de valores, dados, fundos, pagamentos e similares, inclusive entre contas em geral.", + "1517": + "Emissão, fornecimento, devolução, sustação, cancelamento e oposição de cheques quaisquer, avulso ou por talão.", + "1518": + "Serviços relacionados a crédito imobiliário, avaliação e vistoria de imóvel ou obra, análise técnica e jurídica, emissão, reemissão, alteração, transferência e renegociação de contrato, emissão e reemissão do termo de quitação e demais serviços relacionados a crédito imobiliário.", + "1601": + "Serviços de transporte coletivo municipal rodoviário, metroviário, ferroviário e aquaviário de passageiros.", + "1602": "Outros serviços de transporte de natureza municipal.", + "1701": + "Assessoria ou consultoria de qualquer natureza, não contida em outros itens desta lista; análise, exame, pesquisa, coleta, compilação e fornecimento de dados e informações de qualquer natureza, inclusive cadastro e similares.", + "1702": + "Datilografia, digitação, estenografia, expediente, secretaria em geral, resposta audível, redação, edição, interpretação, revisão, tradução, apoio e infra-estrutura administrativa e congêneres.", + "1703": + "Planejamento, coordenação, programação ou organização técnica, financeira ou administrativa.", + "1704": "Recrutamento, agenciamento, seleção e colocação de mão-de-obra.", + "1705": + "Fornecimento de mão-de-obra, mesmo em caráter temporário, inclusive de empregados ou trabalhadores, avulsos ou temporários, contratados pelo prestador de serviço.", + "1706": + "Propaganda e publicidade, inclusive promoção de vendas, planejamento de campanhas ou sistemas de publicidade, elaboração de desenhos, textos e demais materiais publicitários.", + "1708": "Franquia (franchising).", + "1709": "Perícias, laudos, exames técnicos e análises técnicas.", + "1710": + "Planejamento, organização e administração de feiras, exposições, congressos e congêneres.", + "1711": + "Organização de festas e recepções; bufê (exceto o fornecimento de alimentação e bebidas, que fica sujeito ao ICMS).", + "1712": "Administração em geral, inclusive de bens e negócios de terceiros.", + "1713": "Leilão e congêneres.", + "1714": "Advocacia", + "1715": "Arbitragem de qualquer espécie, inclusive jurídica.", + "1716": "Auditoria.", + "1717": "Análise de Organização e Métodos.", + "1718": "Atuária e cálculos técnicos de qualquer natureza.", + "1719": "Contabilidade, inclusive serviços técnicos e auxiliares.", + "1720": "Consultoria e assessoria econômica ou financeira.", + "1721": "Estatística.", + "1722": "Cobrança em geral.", + "1723": + "Assessoria, análise, avaliação, atendimento, consulta, cadastro, seleção, gerenciamento de informações, administração de contas a receber ou a pagar e em geral, relacionados a operações de faturização (factoring).", + "1724": "Apresentação de palestras, conferências, seminários e congêneres.", + "1725": + "Inserção de textos, desenhos e outros materiais de propaganda e publicidade, em qualquer meio (exceto em livros, jornais, periódicos e nas modalidades de serviços de radiodifusão sonora e de sons e imagens de recepção livre e gratuita).", + "1801": + "Serviços de regulação de sinistros vinculados a contratos de seguros; inspeção e avaliação de riscos para cobertura de contratos de seguros; prevenção e gerência de riscos seguráveis e congêneres.", + "1901": + "Serviços de distribuição e venda de bilhetes e demais produtos de loteria, bingos, cartões, pules ou cupons de apostas, sorteios, prêmios, inclusive os decorrentes de títulos de capitalização e congêneres.", + "2001": + "Serviços portuários, ferroportuários, utilização de porto, movimentação de passageiros, reboque de embarcações, rebocador escoteiro, atracação, desatracação, serviços de praticagem, capatazia, armazenagem de qualquer natureza, serviços acessórios, movimentação de mercadorias, serviços de apoio marítimo, de movimentação ao largo, serviços de armadores, estiva, conferência, logística e congêneres.", + "2002": + "Serviços aeroportuários, utilização de aeroporto, movimentação de passageiros, armazenagem de qualquer natureza, capatazia, movimentação de aeronaves, serviços de apoio aeroportuários, serviços acessórios, movimentação de mercadorias, logística e congêneres.", + "2003": + "Serviços de terminais rodoviários, ferroviários, metroviários, movimentação de passageiros, mercadorias, inclusive suas operações, logística e congêneres.", + "2101": "Serviços de registros públicos, cartorários e notariais.", + "2201": + "Serviços de exploração de rodovia mediante cobrança de preço ou pedágio dos usuários, envolvendo execução de serviços de conservação, manutenção, melhoramentos para adequação de capacidade e segurança de trânsito, operação, monitoração, assistência aos usuários e outros serviços definidos em contratos, atos de concessão ou de permissão ou em normas oficiais.", + "2301": "Serviços de programação e comunicação visual, desenho industrial e congêneres.", + "2401": + "Serviços de chaveiros, confecção de carimbos, placas, sinalização visual, banners, adesivos e congêneres.", + "2501": + "Funerais, inclusive fornecimento de caixão, urna ou esquifes; aluguel de capela; transporte do corpo cadavérico; fornecimento de flores, coroas e outros paramentos; desembaraço de certidão de óbito; fornecimento de véu, essa e outros adornos; embalsamento, embelezamento, conservação ou restauração de cadáveres.", + "2502": "Translado intramunicipal e cremação de corpos e partes de corpos cadavéricos.", + "2503": "Planos ou convênio funerários.", + "2504": "Manutenção e conservação de jazigos e cemitérios.", + "2505": "Cessão de uso de espaços em cemitérios para sepultamento.", + "2601": + "Serviços de coleta, remessa ou entrega de correspondências, documentos, objetos, bens ou valores, inclusive pelos correios e suas agências franqueadas; courrier e congêneres.", + "2701": "Serviços de assistência social.", + "2801": "Serviços de avaliação de bens e serviços de qualquer natureza.", + "2901": "Serviços de biblioteconomia.", + "3001": "Serviços de biologia, biotecnologia e química.", + "3101": + "Serviços técnicos em edificações, eletrônica, eletrotécnica, mecânica, telecomunicações e congêneres.", + "3201": "Serviços de desenhos técnicos.", + "3301": "Serviços de desembaraço aduaneiro, comissários, despachantes e congêneres.", + "3401": "Serviços de investigações particulares, detetives e congêneres.", + "3501": "Serviços de reportagem, assessoria de imprensa, jornalismo e relações públicas.", + "3601": "Serviços de meteorologia.", + "3701": "Serviços de artistas, atletas, modelos e manequins.", + "3801": "Serviços de museologia.", + "3901": + "Serviços de ourivesaria e lapidação (quando o material for fornecido pelo tomador do serviço).", + "4001": "Obras de arte sob encomenda.", +}; + +/** + * Shape a subitem has to be written in: one or two digits of the item and the two of the + * subitem, with the dot the law prints between them or without it. + */ +export const SERVICE_ITEM_FORMAT_REGEX = /^\d{1,2}\.?\d{2}$/; diff --git a/src/format-nbs/format-nbs.test.ts b/src/format-nbs/format-nbs.test.ts new file mode 100644 index 00000000..20dcf0cf --- /dev/null +++ b/src/format-nbs/format-nbs.test.ts @@ -0,0 +1,80 @@ +import { anyGarbage, anyValue, digits } from "../_internals/test/arbitraries"; +import { + expectAlwaysReturnsType, + expectIdempotent, + expectMatchesPattern, + expectNeverThrows, +} from "../_internals/test/properties"; +import { describe, expect, expectTypeOf, it, test } from "../_internals/test/runtime"; +import { formatNbs } from "./format-nbs"; + +describe("formatNbs", () => { + it("should format an NBS code given as digits", () => { + expect(formatNbs("101011100")).toBe("1.0101.11.00"); + }); + + it("should format an NBS code given as a number", () => { + expect(formatNbs(126_050_000)).toBe("1.2605.00.00"); + }); + + it("should keep a code that already has the mask", () => { + expect(formatNbs("1.0101.11.00")).toBe("1.0101.11.00"); + }); + + it("should not validate whether the code exists in the official table", () => { + expect(formatNbs("999999999")).toBe("9.9999.99.99"); + }); + + it("should mask a partial value progressively", () => { + expect(formatNbs("1")).toBe("1"); + expect(formatNbs("10")).toBe("1.0"); + expect(formatNbs("10101")).toBe("1.0101"); + expect(formatNbs("101011")).toBe("1.0101.1"); + expect(formatNbs("1010111")).toBe("1.0101.11"); + expect(formatNbs("10101110")).toBe("1.0101.11.0"); + }); + + it("should drop the characters outside the mask and the digits after the ninth", () => { + expect(formatNbs("abc101011100")).toBe("1.0101.11.00"); + expect(formatNbs("1010111009")).toBe("1.0101.11.00"); + }); + + it("should return an empty string when there is no digit", () => { + expect(formatNbs("")).toBe(""); + expect(formatNbs("abc")).toBe(""); + }); + + it("should return an empty string for null and undefined", () => { + // @ts-expect-error not a string or number + expect(formatNbs(null)).toBe(""); + // @ts-expect-error not a string or number + expect(formatNbs()).toBe(""); + }); + + describe("properties", () => { + const nineDigits = digits(9); + + test("should never throw, regardless of the input", () => { + expectNeverThrows(formatNbs, anyGarbage); + }); + + test("should always return a string", () => { + expectAlwaysReturnsType(formatNbs, "string", anyValue); + }); + + test("should format every 9 digit value in the N.NNNN.NN.NN pattern", () => { + expectMatchesPattern(formatNbs, /^\d\.\d{4}\.\d{2}\.\d{2}$/, nineDigits); + }); + + test("should be idempotent on a full 9 digit code", () => { + expectIdempotent(formatNbs, nineDigits); + }); + }); +}); + +describe("formatNbs types", () => { + test("should take a string or number value and return a string", () => { + expectTypeOf(formatNbs).parameters.toEqualTypeOf<[value: string | number]>(); + expectTypeOf(formatNbs).returns.toEqualTypeOf(); + }); +}); diff --git a/src/format-nbs/format-nbs.ts b/src/format-nbs/format-nbs.ts new file mode 100644 index 00000000..075b037f --- /dev/null +++ b/src/format-nbs/format-nbs.ts @@ -0,0 +1,31 @@ +import { format } from "../_internals/format/format"; +import { isNullish } from "../_internals/is-nullish/is-nullish"; +import { sanitizeToDigits } from "../_internals/sanitize-to-digits/sanitize-to-digits"; + +/** + * Formats an NBS (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que + * Produzam Variações no Patrimônio) code into the `N.NNNN.NN.NN` mask the nomenclature prints. + * + * This is a purely structural transformation, it does not check the code against the official + * table, use `isValidNbs` for that. Like every formatter of this package, the value is read for + * its digits and masked as far as they go, so a partial code still being typed is masked + * progressively, characters outside the mask are dropped and anything without a digit gives + * `""` instead of throwing. Every NBS code starts with 1, so there is no zero padding to offer. + * + * @param {string|number} value - The NBS code to be formatted. + * @returns {string} The formatted code in the `N.NNNN.NN.NN` pattern, or an empty string when + * there is nothing to format. + * + * @example + * ```typescript + * formatNbs("101011100"); // "1.0101.11.00" + * formatNbs(101011100); // "1.0101.11.00" + * formatNbs("10101"); // "1.0101" (partial values are masked as far as they go) + * ``` + * + * @see Official: https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/Anexoa_Ia_NBSa_2.0a_coma_alteraa_esa_6.12.18.pdf + * Anexo I of the Portaria Conjunta RFB/SCS 2.000/2018, NBS 2.0: "Formação do código da NBS" and + * the `N.NNNN.NN.NN` form every code of the nomenclature is printed in. + */ +export const formatNbs = (value: string | number): string => + isNullish(value) ? "" : format({ value: sanitizeToDigits(value), pattern: "0.0000.00.00" }); diff --git a/src/get-nbs/get-nbs.test.ts b/src/get-nbs/get-nbs.test.ts new file mode 100644 index 00000000..9a48f9dc --- /dev/null +++ b/src/get-nbs/get-nbs.test.ts @@ -0,0 +1,165 @@ +import * as fc from "fast-check"; + +import { NBS_DESCRIPTIONS } from "../_internals/constants/nbs"; +import { anyGarbage, PROTOTYPE_KEYS } from "../_internals/test/arbitraries"; +import { expectNeverThrows } from "../_internals/test/properties"; +import { describe, expect, expectTypeOf, it, test } from "../_internals/test/runtime"; +import { formatNbs } from "../format-nbs/format-nbs"; +import { isValidNbs } from "../is-valid-nbs/is-valid-nbs"; +import { getNbs, type Nbs } from "./get-nbs"; + +const RESIDENTIAL = { + code: "101011100", + description: "Serviços de construção de edificações residenciais de um e dois pavimentos", +}; + +describe("getNbs", () => { + it("should return the code for the 9 digits without a mask", () => { + expect(getNbs("101011100")).toEqual(RESIDENTIAL); + }); + + it("should return the code for the N.NNNN.NN.NN mask", () => { + expect(getNbs("1.0101.11.00")).toEqual(RESIDENTIAL); + }); + + it("should return the code for a number", () => { + expect(getNbs(101_011_100)).toEqual(RESIDENTIAL); + expect(getNbs(126_050_000)).toEqual({ code: "126050000", description: "Serviços domésticos" }); + }); + + it("should ignore surrounding whitespace", () => { + expect(getNbs(" 1.0101.11.00\n")).toEqual(RESIDENTIAL); + }); + + it("should accept any single mask character between the groups", () => { + expect(getNbs("1 0101 11 00")).toEqual(RESIDENTIAL); + expect(getNbs("1-0101-11-00")).toEqual(RESIDENTIAL); + expect(getNbs("1/0101/11/00")).toEqual(RESIDENTIAL); + expect(getNbs("1.010111.00")).toEqual(RESIDENTIAL); + }); + + it("should resolve the three codes of the NBS 2.0 the ANEXO B of the NFS-e leaves out", () => { + expect(getNbs("1.0904.40.00")).toEqual({ + code: "109044000", + description: "Serviços de retrocessão", + }); + expect(getNbs("1.0402.29.00")?.code).toBe("104022900"); + expect(getNbs("1.0403.29.00")?.code).toBe("104032900"); + }); + + it("should resolve the codes the Portaria 2.000/2018 renumbered and not the ones it replaced", () => { + expect(getNbs("1.0402.11.10")?.code).toBe("104021110"); + expect(getNbs("1.0402.11.90")?.code).toBe("104021190"); + expect(getNbs("1.0402.11.11")).toBeNull(); + expect(getNbs("1.0402.11.19")).toBeNull(); + }); + + it("should return the only description the official CSV quotes, without its CSV quoting", () => { + expect(getNbs("1.1706.24.00")).toEqual({ + code: "117062400", + description: + 'Serviços de distribuição de programas de televisão por assinatura, na modalidade "pague por exibição" (pay-per-view)', + }); + }); + + it("should return a fresh object that does not leak the internal table", () => { + expect(getNbs("101011100")).not.toBe(getNbs("101011100")); + }); + + it("should return null for the chapter, position and subposition headings", () => { + expect(getNbs("1.01")).toBeNull(); + expect(getNbs("1.0101")).toBeNull(); + expect(getNbs("1.0101.1")).toBeNull(); + expect(getNbs("10101")).toBeNull(); + }); + + it("should return null for a 9 digit code the table does not carry", () => { + expect(getNbs("1.9999.99.99")).toBeNull(); + expect(getNbs("9.9999.99.99")).toBeNull(); + expect(getNbs("000000000")).toBeNull(); + }); + + it("should return null for a group boundary written with more than one separator", () => { + expect(getNbs("1..0101.11.00")).toBeNull(); + expect(getNbs("1.0101..11.00")).toBeNull(); + expect(getNbs("1.0101.11..00")).toBeNull(); + }); + + it("should return null for a string that is not written in a documented form", () => { + expect(getNbs("1.0101abc11.00")).toBeNull(); + expect(getNbs("10.101.11.00")).toBeNull(); + expect(getNbs("x101011100")).toBeNull(); + expect(getNbs("101011100x")).toBeNull(); + expect(getNbs("1010111000")).toBeNull(); + expect(getNbs("1,0101,11,00")).toBeNull(); + }); + + it("should return null for an empty string and for whitespace only", () => { + expect(getNbs("")).toBeNull(); + expect(getNbs(" ")).toBeNull(); + }); + + it("should return null for null and undefined", () => { + // @ts-expect-error not a string or number + expect(getNbs(null)).toBeNull(); + // @ts-expect-error not a string or number + expect(getNbs()).toBeNull(); + }); + + it("should return null for a number that is not a non-negative safe integer", () => { + expect(getNbs(-101_011_100)).toBeNull(); + expect(getNbs(101_011_100.5)).toBeNull(); + expect(getNbs(2 ** 53)).toBeNull(); + }); + + it("should return null for the keys of Object.prototype", () => { + for (const key of PROTOTYPE_KEYS) expect(getNbs(key)).toBeNull(); + }); + + describe("properties", () => { + const codeArbitrary = fc.constantFrom(...Object.keys(NBS_DESCRIPTIONS)); + + test("should never throw, regardless of the input", () => { + expectNeverThrows(getNbs, anyGarbage); + }); + + test("should resolve every known code, bare, masked or as a number, and agree with isValidNbs", () => { + fc.assert( + fc.property(codeArbitrary, (code) => { + const expected = { code, description: NBS_DESCRIPTIONS[code] }; + + expect(getNbs(code)).toEqual(expected); + expect(getNbs(Number(code))).toEqual(expected); + expect(getNbs(formatNbs(code))).toEqual(expected); + expect(isValidNbs(code)).toBe(true); + }), + ); + }); + + test("should only carry 9 digit codes starting with 1 and non-empty descriptions", () => { + fc.assert( + fc.property(codeArbitrary, (code) => { + expect(code).toMatch(/^1\d{8}$/); + expect(NBS_DESCRIPTIONS[code].trim()).not.toBe(""); + }), + ); + }); + + test("should carry no description with the quoting of the CSV left on it", () => { + fc.assert( + fc.property(codeArbitrary, (code) => { + expect(NBS_DESCRIPTIONS[code].startsWith('"')).toBe(false); + expect(NBS_DESCRIPTIONS[code]).not.toContain('""'); + }), + ); + }); + }); +}); + +describe("getNbs types", () => { + test("should take a string or number and return an Nbs or null", () => { + expectTypeOf(getNbs).parameter(0).toEqualTypeOf(); + expectTypeOf(getNbs).returns.toEqualTypeOf(); + expectTypeOf().toEqualTypeOf<{ code: string; description: string }>(); + }); +}); diff --git a/src/get-nbs/get-nbs.ts b/src/get-nbs/get-nbs.ts new file mode 100644 index 00000000..a2327a5e --- /dev/null +++ b/src/get-nbs/get-nbs.ts @@ -0,0 +1,67 @@ +import { NBS_DESCRIPTIONS, NBS_FORMAT_REGEX } from "../_internals/constants/nbs"; +import { isLookupCode } from "../_internals/is-lookup-code/is-lookup-code"; +import { sanitizeToDigits } from "../_internals/sanitize-to-digits/sanitize-to-digits"; + +/** + * A code of the NBS (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que + * Produzam Variações no Patrimônio). + */ +export type Nbs = { + /** The 9 digit code, without the `N.NNNN.NN.NN` mask. */ + code: string; + /** The official description, as the NBS 2.0 table prints it. */ + description: string; +}; + +/** + * Looks an NBS (Nomenclatura Brasileira de Serviços, Intangíveis e Outras Operações que + * Produzam Variações no Patrimônio) code up in the official NBS 2.0 table, the code the national + * NFS-e carries in `cNBS`. + * + * An NBS code has 9 digits: the digit 1, two of the chapter, two of the position, the two + * subposition levels, the item and the subitem, printed as `N.NNNN.NN.NN`. Only complete codes + * are in the table; the chapter (`1.01`), position (`1.0101`) and subposition (`1.0101.1`) + * headings classify nothing by themselves and give `null`. + * + * A string is only read as a code when it is written in one of the documented forms: the 9 + * digits, or the `N.NNNN.NN.NN` mask, with a single separator between the groups and optional + * surrounding whitespace. Anything else (`"1.0101abc11.00"`) is rejected instead of having its + * digits picked out. A number is only read as a code when it is a non-negative safe integer. + * Every code starts with 1, so nothing is padded. + * + * @param {string|number} value - The NBS code to look up, with or without the mask, e.g. + * `"1.0101.11.00"`, `"101011100"` or `101011100`. + * @returns {Nbs|null} The matching code, or null when it is unknown or invalid. + * + * @example + * ```typescript + * getNbs("1.0101.11.00"); + * // { code: "101011100", description: "Serviços de construção de edificações residenciais de um e dois pavimentos" } + * getNbs(126050000); // { code: "126050000", description: "Serviços domésticos" } + * getNbs("1.0101"); // null (a position heading, not a complete code) + * getNbs("1.9999.99.99"); // null + * ``` + * + * @see Official: https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos + * The NBS page of the MDIC: NBS 2.0, approved by the Portaria Conjunta RFB/SCS 1.429/2018 and + * amended by the Portaria Conjunta RFB/SCS 2.000/2018, whose Anexo I states how the code is + * formed ("Formação do código da NBS"). + * @see Official: https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/NBSa_2-0.csv + * The NBS 2.0 table in CSV, the file `NBS_DESCRIPTIONS` is generated from. + * @see Official: https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual + * Sistema Nacional NFS-e, `tiposSimples_v1.01.xsd`: `TSCodNBS` is `[0-9]{9}`. + */ +export const getNbs = (value: string | number): Nbs | null => { + if (!isLookupCode(value)) return null; + + const code = String(value).trim(); + + if (!NBS_FORMAT_REGEX.test(code)) return null; + + const digits = sanitizeToDigits(code); + const description = NBS_DESCRIPTIONS[digits]; + + if (description === undefined) return null; + + return { code: digits, description }; +}; diff --git a/src/get-service-item/get-service-item.test.ts b/src/get-service-item/get-service-item.test.ts new file mode 100644 index 00000000..e7328eff --- /dev/null +++ b/src/get-service-item/get-service-item.test.ts @@ -0,0 +1,154 @@ +import * as fc from "fast-check"; + +import { SERVICE_ITEM_DESCRIPTIONS } from "../_internals/constants/service-items"; +import { anyGarbage, PROTOTYPE_KEYS } from "../_internals/test/arbitraries"; +import { expectNeverThrows } from "../_internals/test/properties"; +import { describe, expect, expectTypeOf, it, test } from "../_internals/test/runtime"; +import { isValidServiceItem } from "../is-valid-service-item/is-valid-service-item"; +import { getServiceItem, type ServiceItem } from "./get-service-item"; + +const SYSTEMS = { code: "1.01", description: "Análise e desenvolvimento de sistemas." }; + +describe("getServiceItem", () => { + it("should return the subitem for the form the law prints", () => { + expect(getServiceItem("1.01")).toEqual(SYSTEMS); + expect(getServiceItem("1.02")).toEqual({ code: "1.02", description: "Programação." }); + }); + + it("should return the subitem for a zero padded item", () => { + expect(getServiceItem("01.01")).toEqual(SYSTEMS); + }); + + it("should return the subitem for the bare digits, the first four of a cTribNac", () => { + expect(getServiceItem("0101")).toEqual(SYSTEMS); + expect(getServiceItem("101")).toEqual(SYSTEMS); + expect(getServiceItem(101)).toEqual(SYSTEMS); + }); + + it("should return a two digit item without a leading zero in the code", () => { + expect(getServiceItem("40.01")).toEqual({ + code: "40.01", + description: "Obras de arte sob encomenda.", + }); + expect(getServiceItem(4001)).toEqual({ + code: "40.01", + description: "Obras de arte sob encomenda.", + }); + expect(getServiceItem("10.04")?.code).toBe("10.04"); + }); + + it("should return the subitem 11.05, added by the Lei Complementar 183/2021", () => { + expect(getServiceItem("11.05")?.code).toBe("11.05"); + }); + + it("should ignore surrounding whitespace", () => { + expect(getServiceItem(" 1.01\n")).toEqual(SYSTEMS); + }); + + it("should return the subitem 17.14 as the official sheet prints it, without a final period", () => { + expect(getServiceItem("17.14")).toEqual({ code: "17.14", description: "Advocacia" }); + }); + + it("should return a fresh object that does not leak the internal table", () => { + expect(getServiceItem("1.01")).not.toBe(getServiceItem("1.01")); + }); + + it("should return null for the vetoed subitems", () => { + expect(getServiceItem("3.01")).toBeNull(); + expect(getServiceItem("7.14")).toBeNull(); + expect(getServiceItem("7.15")).toBeNull(); + expect(getServiceItem("13.01")).toBeNull(); + expect(getServiceItem("17.07")).toBeNull(); + }); + + it("should return null for item 99 of the national list, which is not part of the law", () => { + expect(getServiceItem("99.01")).toBeNull(); + }); + + it("should return null for an item heading and for a 6 digit national code", () => { + expect(getServiceItem("1")).toBeNull(); + expect(getServiceItem("01")).toBeNull(); + expect(getServiceItem("010101")).toBeNull(); + expect(getServiceItem("1.01.01")).toBeNull(); + }); + + it("should return null for a subitem the list does not carry", () => { + expect(getServiceItem("1.10")).toBeNull(); + expect(getServiceItem("41.01")).toBeNull(); + expect(getServiceItem("0.01")).toBeNull(); + }); + + it("should return null for a string that is not written in a documented form", () => { + expect(getServiceItem("1.1")).toBeNull(); + expect(getServiceItem("1..01")).toBeNull(); + expect(getServiceItem("1-01")).toBeNull(); + expect(getServiceItem("1,01")).toBeNull(); + expect(getServiceItem("x1.01")).toBeNull(); + expect(getServiceItem("1.01x")).toBeNull(); + expect(getServiceItem("001.01")).toBeNull(); + }); + + it("should return null for an empty string and for whitespace only", () => { + expect(getServiceItem("")).toBeNull(); + expect(getServiceItem(" ")).toBeNull(); + }); + + it("should return null for null and undefined", () => { + // @ts-expect-error not a string or number + expect(getServiceItem(null)).toBeNull(); + // @ts-expect-error not a string or number + expect(getServiceItem()).toBeNull(); + }); + + it("should return null for a number that is not a non-negative safe integer", () => { + expect(getServiceItem(1.01)).toBeNull(); + expect(getServiceItem(-101)).toBeNull(); + expect(getServiceItem(2 ** 53)).toBeNull(); + }); + + it("should return null for the keys of Object.prototype", () => { + for (const key of PROTOTYPE_KEYS) expect(getServiceItem(key)).toBeNull(); + }); + + describe("properties", () => { + const keyArbitrary = fc.constantFrom(...Object.keys(SERVICE_ITEM_DESCRIPTIONS)); + + test("should never throw, regardless of the input", () => { + expectNeverThrows(getServiceItem, anyGarbage); + }); + + test("should resolve every subitem of the table in every documented form and agree with isValidServiceItem", () => { + fc.assert( + fc.property(keyArbitrary, (key) => { + const description = SERVICE_ITEM_DESCRIPTIONS[key]; + const padded = `${key.slice(0, 2)}.${key.slice(2)}`; + const found = getServiceItem(key); + + expect(found?.description).toBe(description); + expect(found?.code).toMatch(/^[1-9]\d?\.\d{2}$/); + expect(getServiceItem(padded)).toEqual(found); + expect(getServiceItem(Number(key))).toEqual(found); + expect(getServiceItem(found?.code ?? "")).toEqual(found); + expect(isValidServiceItem(key)).toBe(true); + }), + ); + }); + + test("should only carry items 01 to 40 and non-empty descriptions", () => { + fc.assert( + fc.property(keyArbitrary, (key) => { + expect(key).toMatch(/^(?:0[1-9]|[1-3]\d|40)\d{2}$/); + expect(SERVICE_ITEM_DESCRIPTIONS[key].trim()).not.toBe(""); + }), + ); + }); + }); +}); + +describe("getServiceItem types", () => { + test("should take a string or number and return a ServiceItem or null", () => { + expectTypeOf(getServiceItem).parameter(0).toEqualTypeOf(); + expectTypeOf(getServiceItem).returns.toEqualTypeOf(); + expectTypeOf().toEqualTypeOf<{ code: string; description: string }>(); + }); +}); diff --git a/src/get-service-item/get-service-item.ts b/src/get-service-item/get-service-item.ts new file mode 100644 index 00000000..6a3d86ed --- /dev/null +++ b/src/get-service-item/get-service-item.ts @@ -0,0 +1,75 @@ +import { + SERVICE_ITEM_DESCRIPTIONS, + SERVICE_ITEM_FORMAT_REGEX, +} from "../_internals/constants/service-items"; +import { isLookupCode } from "../_internals/is-lookup-code/is-lookup-code"; +import { sanitizeToDigits } from "../_internals/sanitize-to-digits/sanitize-to-digits"; + +const SUBITEM_LENGTH = 4; + +const ITEM_LENGTH = 2; + +/** A subitem of the service list annexed to the Lei Complementar 116/2003. */ +export type ServiceItem = { + /** The subitem as the law numbers it, e.g. `"1.01"` or `"17.25"`. */ + code: string; + /** The description of the subitem, as the list in force prints it. */ + description: string; +}; + +/** + * Looks a subitem up in the service list annexed to the Lei Complementar 116/2003, the list of + * the services the ISS is levied on. + * + * The law numbers a subitem as the item, a dot and two digits, `1.01` to `40.01`. It is accepted + * in that form, with a zero padded item (`"01.01"`) or as the bare digits (`"0101"`, `"101"`), + * which are the first four digits of the `cTribNac` code of the national NFS-e, and optional + * surrounding whitespace. The dot is the only separator the law ever prints between the item and + * the subitem, so unlike the codes with a printed grouping mask (`getCfop`, `getNbs`) nothing + * else is accepted in its place and `"1-01"` gives `null`. A number is only read when it is a + * non-negative safe integer, so `101` is `1.01` while the float `1.01` gives `null`: write the + * dotted form as a string. + * + * Only the subitems in force are in the table. The vetoed ones (`3.01`, `7.14`, `7.15`, `13.01` + * and `17.07`) give `null`, and so do the item headings (`"1"`), the national codes a subitem is + * split into (`"010101"`) and item 99 of the national list, which is not part of the law. + * Municipal service codes are out of scope. + * + * @param {string|number} value - The subitem to look up, e.g. `"1.01"`, `"01.01"`, `"0101"` or + * `101`. + * @returns {ServiceItem|null} The matching subitem, or null when it is unknown or invalid. + * + * @example + * ```typescript + * getServiceItem("1.01"); // { code: "1.01", description: "Análise e desenvolvimento de sistemas." } + * getServiceItem("0101"); // { code: "1.01", description: "Análise e desenvolvimento de sistemas." } + * getServiceItem("40.01"); // { code: "40.01", description: "Obras de arte sob encomenda." } + * getServiceItem("3.01"); // null (vetoed) + * getServiceItem(1.01); // null (not a non-negative safe integer) + * ``` + * + * @see Official: https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm + * Lei Complementar 116/2003, "Lista de serviços anexa". + * @see Official: https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual + * Sistema Nacional NFS-e, `ANEXO_B-NBS2-LISTA_SERVICO_NACIONAL`, sheet `LISTA.SERV.NAC.`: the + * list in force in machine readable form, which `SERVICE_ITEM_DESCRIPTIONS` is generated from, + * and `TSCodTribNac` of `tiposSimples_v1.01.xsd`, "2 para Item (LC 116/2003), 2 para Subitem (LC + * 116/2003) e 2 para Desdobro Nacional". + */ +export const getServiceItem = (value: string | number): ServiceItem | null => { + if (!isLookupCode(value)) return null; + + const written = String(value).trim(); + + if (!SERVICE_ITEM_FORMAT_REGEX.test(written)) return null; + + const digits = sanitizeToDigits(written).padStart(SUBITEM_LENGTH, "0"); + const description = SERVICE_ITEM_DESCRIPTIONS[digits]; + + if (description === undefined) return null; + + return { + code: `${Number(digits.slice(0, ITEM_LENGTH))}.${digits.slice(ITEM_LENGTH)}`, + description, + }; +}; diff --git a/src/index.test.ts b/src/index.test.ts index 0cecaa9d..e319d1fd 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -82,6 +82,7 @@ import { type LegalNatureCategory, type LicensePlateFormat, type Municipality, + type Nbs, type NfeKeyInfo, type NfeKeyModel, type NfseKeyGeneratorEnvironment, @@ -98,6 +99,7 @@ import { type PixPayloadInfo, type PixPointOfInitiation, type RegistroProfissionalCouncil, + type ServiceItem, type State, type StateCode, type StandardSchemaV1, @@ -147,6 +149,7 @@ const PUBLIC = [ "formatIban", "formatLegalNature", "formatLicensePlate", + "formatNbs", "formatNcm", "formatNfeKey", "formatPassport", @@ -198,12 +201,14 @@ const PUBLIC = [ "getMunicipalities", "getMunicipality", "getMunicipalityByCode", + "getNbs", "getNextBusinessDay", "getNfeKeyInfo", "getNfseKeyInfo", "getNthBusinessDay", "getPixKeyInfo", "getPixPayloadInfo", + "getServiceItem", "getStateByCep", "getStateByIbgeCode", "getStateCodeByName", @@ -241,6 +246,7 @@ const PUBLIC = [ "isValidLegalNature", "isValidLicensePlate", "isValidMobilePhone", + "isValidNbs", "isValidNcm", "isValidNfeKey", "isValidNfseKey", @@ -253,6 +259,7 @@ const PUBLIC = [ "isValidProcessoJuridico", "isValidRegistroProfissional", "isValidRenavam", + "isValidServiceItem", "isValidServicePhone", "isValidSuframa", "isValidVin", @@ -399,6 +406,7 @@ describe("Public API", () => { LegalNatureCategory: LegalNatureCategory; LicensePlateFormat: LicensePlateFormat; Municipality: Municipality; + Nbs: Nbs; NfeKeyInfo: NfeKeyInfo; NfeKeyModel: NfeKeyModel; NfseKeyGeneratorEnvironment: NfseKeyGeneratorEnvironment; @@ -415,6 +423,7 @@ describe("Public API", () => { PixPayloadInfo: PixPayloadInfo; PixPointOfInitiation: PixPointOfInitiation; RegistroProfissionalCouncil: RegistroProfissionalCouncil; + ServiceItem: ServiceItem; State: State; StateCode: StateCode; StandardSchemaV1: StandardSchemaV1; diff --git a/src/index.ts b/src/index.ts index 9d2245ac..df01a6a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,6 +44,7 @@ export { formatLegalNature, } from "./format-legal-nature/format-legal-nature"; export { formatLicensePlate } from "./format-license-plate/format-license-plate"; +export { formatNbs } from "./format-nbs/format-nbs"; export { type FormatNcmOptions, formatNcm } from "./format-ncm/format-ncm"; export { type FormatNfeKeyOptions, formatNfeKey } from "./format-nfe-key/format-nfe-key"; export { formatPassport } from "./format-passport/format-passport"; @@ -154,6 +155,7 @@ export { getMunicipality, } from "./get-municipality/get-municipality"; export { getMunicipalityByCode } from "./get-municipality-by-code/get-municipality-by-code"; +export { type Nbs, getNbs } from "./get-nbs/get-nbs"; export { getNextBusinessDay } from "./get-next-business-day/get-next-business-day"; export { type NfeKeyInfo, @@ -177,6 +179,7 @@ export { type PixPointOfInitiation, getPixPayloadInfo, } from "./get-pix-payload-info/get-pix-payload-info"; +export { type ServiceItem, getServiceItem } from "./get-service-item/get-service-item"; export { getStateByCep } from "./get-state-by-cep/get-state-by-cep"; export { getStateByIbgeCode } from "./get-state-by-ibge-code/get-state-by-ibge-code"; export { getStateCodeByName } from "./get-state-code-by-name/get-state-code-by-name"; @@ -219,6 +222,7 @@ export { type IsValidMobilePhoneOptions, isValidMobilePhone, } from "./is-valid-mobile-phone/is-valid-mobile-phone"; +export { isValidNbs } from "./is-valid-nbs/is-valid-nbs"; export { isValidNcm } from "./is-valid-ncm/is-valid-ncm"; export { isValidNfeKey } from "./is-valid-nfe-key/is-valid-nfe-key"; export { isValidNfseKey } from "./is-valid-nfse-key/is-valid-nfse-key"; @@ -239,6 +243,7 @@ export { isValidRegistroProfissional, } from "./is-valid-registro-profissional/is-valid-registro-profissional"; export { isValidRenavam } from "./is-valid-renavam/is-valid-renavam"; +export { isValidServiceItem } from "./is-valid-service-item/is-valid-service-item"; export { isValidServicePhone } from "./is-valid-service-phone/is-valid-service-phone"; export { isValidSuframa } from "./is-valid-suframa/is-valid-suframa"; export { isValidVin } from "./is-valid-vin/is-valid-vin"; diff --git a/src/is-valid-nbs/is-valid-nbs.test.ts b/src/is-valid-nbs/is-valid-nbs.test.ts new file mode 100644 index 00000000..90cf28d8 --- /dev/null +++ b/src/is-valid-nbs/is-valid-nbs.test.ts @@ -0,0 +1,63 @@ +import { anyGarbage, anyValue } from "../_internals/test/arbitraries"; +import { expectAlwaysReturnsType, expectNeverThrows } from "../_internals/test/properties"; +import { describe, expect, expectTypeOf, it, test } from "../_internals/test/runtime"; +import { isValidNbs } from "./is-valid-nbs"; + +describe("isValidNbs", () => { + it("should validate an NBS code without a mask", () => { + expect(isValidNbs("101011100")).toBe(true); + }); + + it("should validate an NBS code with the N.NNNN.NN.NN mask", () => { + expect(isValidNbs("1.0101.11.00")).toBe(true); + expect(isValidNbs("1.2606.00.00")).toBe(true); + }); + + it("should validate an NBS code given as a number", () => { + expect(isValidNbs(101_011_100)).toBe(true); + }); + + it("should reject the headings of the nomenclature", () => { + expect(isValidNbs("1.01")).toBe(false); + expect(isValidNbs("1.0101")).toBe(false); + expect(isValidNbs("1.0101.1")).toBe(false); + }); + + it("should reject a well formed code the table does not carry", () => { + expect(isValidNbs("1.9999.99.99")).toBe(false); + expect(isValidNbs("1.0101.11.01")).toBe(false); + }); + + it("should reject a malformed value", () => { + expect(isValidNbs("1.0101abc11.00")).toBe(false); + expect(isValidNbs("1..0101.11.00")).toBe(false); + expect(isValidNbs("")).toBe(false); + }); + + it("should reject null, undefined and non lookup values", () => { + // @ts-expect-error not a string or number + expect(isValidNbs(null)).toBe(false); + // @ts-expect-error not a string or number + expect(isValidNbs()).toBe(false); + // @ts-expect-error not a string or number + expect(isValidNbs(["101011100"])).toBe(false); + expect(isValidNbs(-101_011_100)).toBe(false); + }); + + describe("properties", () => { + test("should never throw, regardless of the input", () => { + expectNeverThrows(isValidNbs, anyGarbage); + }); + + test("should always return a boolean", () => { + expectAlwaysReturnsType(isValidNbs, "boolean", anyValue); + }); + }); +}); + +describe("isValidNbs types", () => { + test("should take a string or number and return a boolean", () => { + expectTypeOf(isValidNbs).parameter(0).toEqualTypeOf(); + expectTypeOf(isValidNbs).returns.toEqualTypeOf(); + }); +}); diff --git a/src/is-valid-nbs/is-valid-nbs.ts b/src/is-valid-nbs/is-valid-nbs.ts new file mode 100644 index 00000000..d8f8f828 --- /dev/null +++ b/src/is-valid-nbs/is-valid-nbs.ts @@ -0,0 +1,35 @@ +import { getNbs } from "../get-nbs/get-nbs"; + +/** + * Checks if a value is a code of the official NBS 2.0 table (Nomenclatura Brasileira de + * Serviços, Intangíveis e Outras Operações que Produzam Variações no Patrimônio), the code the + * national NFS-e carries in `cNBS`. + * + * Accepts what `getNbs` accepts: the 9 digits or the `N.NNNN.NN.NN` mask, with a single + * separator between the groups and optional surrounding whitespace, or a non-negative safe + * integer. Only complete codes are valid; the chapter, position and subposition headings of the + * nomenclature are not. + * + * The table is the NBS 2.0 the MDIC publishes. The ANEXO B of the Sistema Nacional NFS-e lists + * the same codes except three (`1.0402.29.00`, `1.0403.29.00` and `1.0904.40.00`), so a code + * valid here can still be refused by the NFS-e. + * + * @param {string|number} value - The NBS code to be validated. + * @returns {boolean} True if the code is in the table, false otherwise. + * + * @example + * ```typescript + * isValidNbs("1.0101.11.00"); // true + * isValidNbs("101011100"); // true + * isValidNbs(101011100); // true + * isValidNbs("1.0101"); // false (a position heading, not a complete code) + * isValidNbs("1.9999.99.99"); // false + * ``` + * + * @see Official: https://www.gov.br/mdic/pt-br/assuntos/sdic/comercio-e-servicos/nbs-nomenclatura-brasileira-de-servicos + * The NBS page of the MDIC: NBS 2.0, approved by the Portaria Conjunta RFB/SCS 1.429/2018 and + * amended by the Portaria Conjunta RFB/SCS 2.000/2018. + * @see Official: https://www.gov.br/mdic/pt-br/images/REPOSITORIO/scs/decos/NBS/NBSa_2-0.csv + * The NBS 2.0 table in CSV. + */ +export const isValidNbs = (value: string | number): boolean => getNbs(value) !== null; diff --git a/src/is-valid-service-item/is-valid-service-item.test.ts b/src/is-valid-service-item/is-valid-service-item.test.ts new file mode 100644 index 00000000..1405eb69 --- /dev/null +++ b/src/is-valid-service-item/is-valid-service-item.test.ts @@ -0,0 +1,61 @@ +import { anyGarbage, anyValue } from "../_internals/test/arbitraries"; +import { expectAlwaysReturnsType, expectNeverThrows } from "../_internals/test/properties"; +import { describe, expect, expectTypeOf, it, test } from "../_internals/test/runtime"; +import { isValidServiceItem } from "./is-valid-service-item"; + +describe("isValidServiceItem", () => { + it("should validate a subitem in the form the law prints", () => { + expect(isValidServiceItem("1.01")).toBe(true); + expect(isValidServiceItem("17.25")).toBe(true); + expect(isValidServiceItem("40.01")).toBe(true); + }); + + it("should validate a zero padded item and the bare digits", () => { + expect(isValidServiceItem("01.01")).toBe(true); + expect(isValidServiceItem("0101")).toBe(true); + expect(isValidServiceItem(101)).toBe(true); + }); + + it("should reject the vetoed subitems", () => { + expect(isValidServiceItem("3.01")).toBe(false); + expect(isValidServiceItem("17.07")).toBe(false); + }); + + it("should reject item 99 of the national list and the 6 digit national codes", () => { + expect(isValidServiceItem("99.01")).toBe(false); + expect(isValidServiceItem("010101")).toBe(false); + }); + + it("should reject a malformed value", () => { + expect(isValidServiceItem("1.1")).toBe(false); + expect(isValidServiceItem("1-01")).toBe(false); + expect(isValidServiceItem("")).toBe(false); + }); + + it("should reject null, undefined and non lookup values", () => { + // @ts-expect-error not a string or number + expect(isValidServiceItem(null)).toBe(false); + // @ts-expect-error not a string or number + expect(isValidServiceItem()).toBe(false); + // @ts-expect-error not a string or number + expect(isValidServiceItem(["1.01"])).toBe(false); + expect(isValidServiceItem(1.01)).toBe(false); + }); + + describe("properties", () => { + test("should never throw, regardless of the input", () => { + expectNeverThrows(isValidServiceItem, anyGarbage); + }); + + test("should always return a boolean", () => { + expectAlwaysReturnsType(isValidServiceItem, "boolean", anyValue); + }); + }); +}); + +describe("isValidServiceItem types", () => { + test("should take a string or number and return a boolean", () => { + expectTypeOf(isValidServiceItem).parameter(0).toEqualTypeOf(); + expectTypeOf(isValidServiceItem).returns.toEqualTypeOf(); + }); +}); diff --git a/src/is-valid-service-item/is-valid-service-item.ts b/src/is-valid-service-item/is-valid-service-item.ts new file mode 100644 index 00000000..6b6c8917 --- /dev/null +++ b/src/is-valid-service-item/is-valid-service-item.ts @@ -0,0 +1,32 @@ +import { getServiceItem } from "../get-service-item/get-service-item"; + +/** + * Checks if a value is a subitem in force of the service list annexed to the Lei Complementar + * 116/2003, the list of the services the ISS is levied on. + * + * Accepts what `getServiceItem` accepts: the form the law prints (`"1.01"`), a zero padded item + * (`"01.01"`), the bare digits (`"0101"`, `"101"` or the integer `101`), with optional + * surrounding whitespace. The dot is the only separator the law ever prints, so `"1-01"` is not + * valid. Vetoed subitems, item headings, the 6 digit national codes of the NFS-e and item 99 of + * the national list are not valid. + * + * @param {string|number} value - The subitem to be validated. + * @returns {boolean} True if the subitem is in the list in force, false otherwise. + * + * @example + * ```typescript + * isValidServiceItem("1.01"); // true + * isValidServiceItem("0101"); // true + * isValidServiceItem("17.25"); // true + * isValidServiceItem("3.01"); // false (vetoed) + * isValidServiceItem("99.01"); // false (national list only, not the law) + * ``` + * + * @see Official: https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp116.htm + * Lei Complementar 116/2003, "Lista de serviços anexa". + * @see Official: https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica/documentacao-atual + * Sistema Nacional NFS-e, `ANEXO_B-NBS2-LISTA_SERVICO_NACIONAL`, sheet `LISTA.SERV.NAC.`: the + * list in force in machine readable form. + */ +export const isValidServiceItem = (value: string | number): boolean => + getServiceItem(value) !== null;