{
  "id": "helper-numbertowordshelper",
  "title": "Helper — NumberToWordsHelper",
  "description": "Conversão determinística de números e valores em reais para texto por extenso.",
  "type": "technical-reference",
  "status": "implemented",
  "visibility": "public",
  "tags": [
    "sge/helpers",
    "sge/documentos",
    "sge/formatacao"
  ],
  "related": [
    "helper-currencyhelper",
    "migration-16-generated-documents"
  ],
  "sourceRefs": [
    "https://github.com/sge-suite/sge/blob/master/app/Helpers/NumberToWordsHelper.php",
    "https://github.com/sge-suite/sge/blob/master/tests/Unit/Helpers/NumberToWordsHelperTest.php"
  ],
  "authors": [],
  "updated": null,
  "diagram": null,
  "body": "## Responsabilidade\n\nCentralizar a escrita em português de números usados nos documentos. A implementação usa `Brick\\Math\\BigDecimal` para o valor monetário e `Illuminate\\Support\\Number` para escrever números. Não decide cláusulas, não consulta banco e não formata valores para persistência.\n\n| Método | Entrada | Saída |\n| --- | --- | --- |\n| `cardinal()` | inteiro não negativo | número por extenso em português, como `cento e vinte`. |\n| `brl()` | `string`, `int` ou `Brick\\Math\\BigDecimal` não negativo | valor completo, como `mil e duzentos reais e cinquenta centavos`. |\n\n`brl()` será usado por `RemunerationParagraphFormatter`, que monta o §1º de remuneração em `${PARAGRAFO_REMUNERACAO}`, junto a [`CurrencyHelper`](doc:helper-currencyhelper) para o valor `R$ 1.200,50`.\n\n## Implementação atual\n\n- `cardinal()` rejeita inteiros negativos e delega a escrita para `Number::spell()`; se a conversão falhar, lança `RuntimeException`.\n- `brl()` normaliza a entrada com `BigDecimal::of()` e `toScale(2)`, sem arredondar valores que tenham fração menor que um centavo.\n- o locale de `Number::spell()` é o locale global configurado em `AppServiceProvider` por `Number::useLocale(config('app.locale'))`; o ambiente atual utiliza `pt_BR`.\n- valores monetários negativos, inválidos ou com mais de duas casas decimais são rejeitados com `InvalidArgumentException`.\n- `currencyPart()` aplica singular/plural de `real` e `centavo`; `brl()` omite a parcela igual a zero, exceto para o total `zero reais`.\n\n## Regras\n\n- usar `Number::spell()` com o locale global configurado no `AppServiceProvider` — atualmente `pt_BR` — e tratamento explícito de reais e centavos;\n- receber valores monetários como `string`, `int` ou `BigDecimal`, nunca como `float`;\n- normalizar valores com escala exata de duas casas, rejeitando entradas que exigiriam arredondamento;\n- omitir a parcela igual a zero quando houver apenas reais ou apenas centavos; o valor total zero é `zero reais`;\n- lançar `InvalidArgumentException` para negativos e entradas inválidas;\n- tratar zero, um real, um centavo, negativos e valores sem centavos nos testes;\n- não criar texto jurídico: o §1º é responsabilidade do serviço de documentos.\n\n## Checklist\n\n- [x] Definir uso no §1º de remuneração.\n- [x] Implementar `cardinal()` e `brl()`.\n- [x] Expor `numberToWords()` e `brlToWords()` em `app/helpers.php` para leitura em Blade.\n- [x] Cobrir plurais, zeros, centavos e entradas inválidas com testes unitários.\n- [x] Confirmar disponibilidade da extensão `intl` no ambiente de desenvolvimento.\n- [ ] Confirmar disponibilidade da extensão `intl` na imagem/ambiente de produção.\n\n## Relacionamentos\n\n- [CurrencyHelper](doc:helper-currencyhelper)\n- [Documentos gerados](doc:migration-16-generated-documents)",
  "sections": [
    {
      "id": "responsabilidade",
      "level": 2,
      "title": "Responsabilidade",
      "text": "Centralizar a escrita em português de números usados nos documentos. A implementação usa `Brick\\Math\\BigDecimal` para o valor monetário e `Illuminate\\Support\\Number` para escrever números. Não decide cláusulas, não consulta banco e não formata valores para persistência.  | Método | Entrada | Saída | | --- | --- | --- | | `cardinal()` | inteiro não negativo | número por extenso em português, como `cento e vinte`. | | `brl()` | `string`, `int` ou `Brick\\Math\\BigDecimal` não negativo | valor completo, como `mil e duzentos reais e cinquenta centavos`. |  `brl()` será usado por `RemunerationParagraphFormatter`, que monta o §1º de remuneração em `${PARAGRAFO_REMUNERACAO}`, junto a [`CurrencyHelper`](doc:helper-currencyhelper) para o valor `R$ 1.200,50`.",
      "line": 1
    },
    {
      "id": "implementacao-atual",
      "level": 2,
      "title": "Implementação atual",
      "text": "- `cardinal()` rejeita inteiros negativos e delega a escrita para `Number::spell()`; se a conversão falhar, lança `RuntimeException`. - `brl()` normaliza a entrada com `BigDecimal::of()` e `toScale(2)`, sem arredondar valores que tenham fração menor que um centavo. - o locale de `Number::spell()` é o locale global configurado em `AppServiceProvider` por `Number::useLocale(config('app.locale'))`; o ambiente atual utiliza `pt_BR`. - valores monetários negativos, inválidos ou com mais de duas casas decimais são rejeitados com `InvalidArgumentException`. - `currencyPart()` aplica singular/plural de `real` e `centavo`; `brl()` omite a parcela igual a zero, exceto para o total `zero reais`.",
      "line": 12
    },
    {
      "id": "regras",
      "level": 2,
      "title": "Regras",
      "text": "- usar `Number::spell()` com o locale global configurado no `AppServiceProvider` — atualmente `pt_BR` — e tratamento explícito de reais e centavos; - receber valores monetários como `string`, `int` ou `BigDecimal`, nunca como `float`; - normalizar valores com escala exata de duas casas, rejeitando entradas que exigiriam arredondamento; - omitir a parcela igual a zero quando houver apenas reais ou apenas centavos; o valor total zero é `zero reais`; - lançar `InvalidArgumentException` para negativos e entradas inválidas; - tratar zero, um real, um centavo, negativos e valores sem centavos nos testes; - não criar texto jurídico: o §1º é responsabilidade do serviço de documentos.",
      "line": 20
    },
    {
      "id": "checklist",
      "level": 2,
      "title": "Checklist",
      "text": "- [x] Definir uso no §1º de remuneração. - [x] Implementar `cardinal()` e `brl()`. - [x] Expor `numberToWords()` e `brlToWords()` em `app/helpers.php` para leitura em Blade. - [x] Cobrir plurais, zeros, centavos e entradas inválidas com testes unitários. - [x] Confirmar disponibilidade da extensão `intl` no ambiente de desenvolvimento. - [ ] Confirmar disponibilidade da extensão `intl` na imagem/ambiente de produção.",
      "line": 30
    },
    {
      "id": "relacionamentos",
      "level": 2,
      "title": "Relacionamentos",
      "text": "- [CurrencyHelper](doc:helper-currencyhelper) - [Documentos gerados](doc:migration-16-generated-documents)",
      "line": 39
    }
  ],
  "sourcePath": "content/helper-numbertowordshelper.md",
  "visuals": [],
  "apiVersion": 1
}
