Pular para o conteúdo

Formulário fiscal

Os dados fiscais do seu cliente, validados enquanto ele digita, com as mesmas regras que o Cord usa ao faturar.

O Fiscal Element captura os dados fiscais do destinatário: a quem a fatura é emitida. Ele valida no navegador com o mesmo código com que o servidor do Cord valida antes de salvar; portanto, o que o formulário aceita é exatamente o que o Cord aceita. Um RFC com o dígito verificador digitado errado é detectado na digitação, não dias depois, quando a timbragem o rejeita.

Quais campos pede e o que valida

País Campos Regras
México (MX) RFC, nome ou razão social, regime fiscal, uso do CFDI, código postal fiscal Formato, data e dígito verificador do RFC. O tipo de RFC (12 caracteres, pessoa jurídica; 13, pessoa física) filtra os regimes e usos aplicáveis. XAXX010101000 e XEXX010101000 (público em geral e estrangeiros) fixam o regime 616 e o uso S01. Aviso se a razão social de uma pessoa jurídica trouxer o tipo societário (“S.A. de C.V.”). Código postal de 5 dígitos.
Espanha (ES) NIF / CIF, nome ou razão social, código postal Letra de controle do NIF e do NIE, e dígito de controle do CIF. Código postal de 5 dígitos.
Estados Unidos (US) EIN, nome legal, ZIP EIN válido. ZIP de 5 dígitos ou 12345-6789.
Outro país Identificação fiscal, nome Só se valida que existam, com um aviso unsupported_country.

Regimes do catálogo: 601, 603, 605, 606, 612, 616, 620, 621 e 626. Usos do CFDI: G01, G03, I01, I02, I04, I08, S01 e CP01.

Quando é válido, o resultado é o destinatário normalizado:

{
  "country": "MX",
  "tax_id": "EKU9003173C9",
  "legal_name": "ESCUELA KEMPER URGATE",
  "regimen_fiscal": "601",
  "uso_cfdi": "G03",
  "cp_fiscal": "42501"
}

Fora do México, regimen_fiscal e uso_cfdi chegam como null.

Web Component: <cord-fiscal-form>

Importar @flouviahq/elements registra <cord-fiscal-form> junto com <cord-quote> e <cord-invoice>.

<script type="module" src="https://unpkg.com/@flouviahq/elements/dist/index.mjs"></script>

<form id="signup" method="post" action="/clients">
  <cord-fiscal-form name="recipient" country="MX" lang="en"></cord-fiscal-form>
  <button type="submit">Save</button>
</form>

É um elemento associado a formulários: dentro de um <form>, fornece o seu valor sob o atributo name (o JSON do destinatário normalizado) e bloqueia o envio enquanto houver erros, como um <input required>. O navegador mostra o primeiro erro junto ao campo que o causa. No Safari anterior ao 16.4, que não tem essa API, o formulário funciona, mas não participa do envio: leia value você mesmo.

Atributo Valores
country MX (padrão), ES, US ou outro código ISO. Alterá-lo mantém o que já foi digitado.
lang es, en, pt, fr ou de; outro valor cai para en. Sem ele, o lang da sua página.
name O nome com que fornece o seu valor ao formulário.
Propriedade ou método O que faz
value O destinatário normalizado, se for válido; caso contrário, null.
state O estado completo: valores, campos tocados, erros visíveis, regimes e usos disponíveis.
setValues(data) Carrega valores iniciais, por exemplo de um cliente já salvo.
submit() Mostra todos os erros e devolve o destinatário, se for válido, ou null.
<script type="module">
  const fiscal = document.querySelector('cord-fiscal-form');
  fiscal.setValues({ tax_id: 'EKU9003173C9', legal_name: 'ESCUELA KEMPER URGATE', cp_fiscal: '42501' });

  fiscal.addEventListener('fiscalvalid', (e) => {
    console.log('Recipient ready:', e.detail);
  });
  fiscal.addEventListener('fiscalchange', (e) => {
    console.log('Visible errors:', e.detail.visibleErrors);
  });
</script>
Evento detail
fiscalchange O estado completo, a cada alteração.
fiscalvalid O destinatário normalizado, toda vez que fica válido.

Os erros aparecem apenas nos campos que a pessoa já tocou, ou em todos depois de submit().

Estilos

O formulário vive em um Shadow DOM. Ele é personalizado com partes e variáveis:

cord-fiscal-form::part(label) { font-weight: 500; }
cord-fiscal-form::part(input) { min-height: 48px; }
cord-fiscal-form::part(error) { font-size: 13px; }

cord-fiscal-form {
  --cord-color-primary: #0a192f;
  --cord-border-radius: 10px;
}
Parte Elemento
field O contêiner de cada campo.
label O rótulo.
input O campo de texto ou o seletor.
error A mensagem de erro de um campo.
warning O aviso de um campo (por exemplo, o tipo societário na razão social).

Variáveis: --cord-font-family, --cord-color-text, --cord-color-text-secondary, --cord-color-input, --cord-color-primary, --cord-color-danger e --cord-border-radius.

React: <CordFiscalForm> e <CordBuilder fiscal>

import { CordFiscalForm } from '@flouviahq/elements/react';

export function TaxDetails({ onReady }: { onReady: (recipient: unknown) => void }) {
  return (
    <CordFiscalForm
      country="MX"
      locale="en"
      title="Billing details"
      initial={{ tax_id: 'EKU9003173C9' }}
      onValid={onReady}
    />
  );
}
Prop Detalhe
country MX por padrão.
initial Valores iniciais.
locale es, en, pt, fr ou de.
title Cabeçalho da seção.
onValid É chamada com o destinatário normalizado toda vez que fica válido.
className, style Para o contêiner.

Dentro do Builder, fiscal adiciona a seção e o destinatário viaja com o orçamento:

<CordProvider publishableKey="pk_test_...">
  <CordBuilder fiscal />
</CordProvider>

O país vem da configuração fiscal da sua organização. Se o destinatário não for válido, o Builder não envia e marca os campos com erro. Para controlar o estado você mesmo, useFiscalForm() devolve o mesmo estado que o componente.

Vue: useCordFiscalForm

<script setup>
import { useCordFiscalForm } from '@flouviahq/elements/vue';

const { state, form } = useCordFiscalForm({ country: 'MX' });

function save() {
  const recipient = form.submit();
  if (recipient) console.log(recipient);
}
</script>

<template>
  <label>
    RFC
    <input :value="state.values.tax_id" @input="form.set('tax_id', $event.target.value)" @blur="form.touch('tax_id')" />
  </label>
  <p v-for="e in state.visibleErrors" :key="e.field">{{ e.field }}: {{ e.code }}</p>
  <button @click="save">Save</button>
</template>

state é um ShallowRef com o estado do formulário; form é o formulário headless (set, touch, submit). Para desenhar o texto de cada erro, use fiscalText() de @flouviahq/elements/headless.

Códigos de validação

Código Significado
required O dado está faltando.
too_long Passa do máximo (20 caracteres para a identificação, 300 para o nome).
invalid_tax_id A identificação fiscal não é válida para o país.
invalid_postal_code O código postal não tem o formato do país.
regimen_not_for_persona O regime não corresponde ao tipo de RFC.
uso_not_for_persona O uso do CFDI não corresponde ao tipo de RFC.
generic_requires_616_s01 Um RFC genérico exige o regime 616 e o uso S01.
legal_name_has_regime_suffix Aviso: a razão social traz o tipo societário.
unsupported_country Aviso: para esse país só se valida que o dado exista.

No lado do servidor

  • POST /api/v1/cotizaciones aceita o destinatário em cliente.fiscal. Se não for válido, responde 400 com code: "invalid_fiscal_data" e a lista em issues:

    {
      "error": "Los datos fiscales del cliente no son válidos.",
      "code": "invalid_fiscal_data",
      "issues": [{ "field": "tax_id", "code": "invalid_tax_id" }]
    }
  • @flouviahq/node exporta validateFiscalReceptor(), validRfc(), validSpainTaxId() e validEin(), para validar no seu servidor com o mesmo código.

  • O servidor MCP tem a ferramenta validar_datos_fiscales.