Skip to content

Repository files navigation

react-native-pos-br

npm license zero dependencies

Uma API só para pagar, imprimir e escanear em terminais de POS brasileiros.

O ecossistema de maquininha em React Native é fragmentado: cada fabricante tem SDK próprio, com nome de método diferente, código de erro cru e nenhum contrato em comum. Se você troca de PagBank para Sunmi, reescreve a camada inteira. Este pacote existe para isso não acontecer.

🇬🇧 English version

Instalação

O pacote não tem dependência nenhuma. Você instala só o SDK do fabricante que usa:

npm install react-native-pos-br

# PagBank / PagSeguro (PlugPag SmartPOS)
npm install @lucasmaffei/react-native-plugpag

# Sunmi
npm install @mitsuharu/react-native-sunmi-printer-library

Os dois são peerDependencies opcionais. Quem só usa Sunmi nunca baixa o nativo do PagBank.

Uso

Registre os adapters uma vez, na inicialização do app:

import { registerAdapter } from 'react-native-pos-br';
import { PagBankAdapter } from 'react-native-pos-br/pagbank';
import { SunmiAdapter } from 'react-native-pos-br/sunmi';

registerAdapter(PagBankAdapter);
registerAdapter(SunmiAdapter);

Depois é só usar os hooks. Eles não sabem o fabricante:

import { usePayment, usePrinter, useCapabilities } from 'react-native-pos-br';

function Checkout() {
  const { capabilities } = useCapabilities();
  const { pay, progress, busy, error } = usePayment();
  const { print } = usePrinter();

  async function cobrar() {
    const result = await pay({
      amountInCents: 1050, // R$ 10,50 — sempre centavos inteiros
      method: 'credit',
      reference: 'pedido-42',
    });

    if (result?.status !== 'approved') return;

    await print([
      { type: 'text', value: 'MEU BAR', align: 'center', bold: true },
      { type: 'divider' },
      { type: 'columns', cells: ['Cerveja', 'R$ 10,50'], widths: [3, 1] },
      { type: 'qrcode', value: `https://meubar.app/n/${result.acquirer.hostNsu}` },
      { type: 'feed', lines: 2 },
      { type: 'cut' },
    ]);
  }

  return (
    <Button
      title={busy ? traduzir(progress.stage) : 'Cobrar'}
      onPress={cobrar}
      disabled={busy || !capabilities.includes('payment')}
    />
  );
}

Por que capability e não "terminal"

Porque os aparelhos não são da mesma categoria, e uma interface única de "terminal" obrigaria um deles a mentir:

PagBank (PlugPag) Sunmi
payment (o pagamento vem de outro adquirente)
printer
scanner
nfc

Cada adapter declara só o que implementa, e useCapabilities() diz o que existe neste aparelho. Você esconde o botão de estorno em vez de descobrir na mão do operador que a função não existe.

O que o pacote resolve

Valor sempre em centavos inteiros. amountInCents: 10.5 é recusado com INVALID_ARGUMENT antes de chegar no hardware. Float em dinheiro é bug esperando a hora.

Erro normalizado. O PlugPag devolve número sem documentação consistente; o Sunmi rejeita com string. Aqui tudo chega como PosError com um code estável — e o código cru do fabricante fica em rawCode, para o seu suporte:

import { isPosError } from 'react-native-pos-br';

if (isPosError(error) && error.code === 'PRINTER_OUT_OF_PAPER') {
  avisarOperador('Troque a bobina');
}

Códigos: NOT_AVAILABLE, NOT_ACTIVATED, ABORTED, DECLINED, INVALID_ARGUMENT, PRINTER_OUT_OF_PAPER, PRINTER_OVERHEATED, PRINTER_NOT_READY, HARDWARE, TIMEOUT, UNKNOWN.

Cancelamento não é recusa. Cliente que aperta "cancelar" gera PosError('ABORTED'), não um resultado declined. São coisas diferentes no seu relatório.

Toque duplo não cobra duas vezes. usePayment serializa: a segunda chamada durante uma transação em andamento devolve null sem tocar no terminal.

Impressão declarativa e portável. Você descreve o cupom; cada adapter renderiza com o que tem. columns no Sunmi usa a API nativa de colunas; no PagBank, que só imprime string, degrada para texto monoespacado alinhado. cut é ignorado em terminal sem guilhotina. Nada falha silenciosamente por falta de recurso.

Peer ausente não derruba o app. Se o SDK do fabricante não está instalado, isAvailable() devolve false e as operações lançam NOT_AVAILABLE com a instrução de instalação — em vez de estourar na importação.

API

Export O que é
registerAdapter(adapter) Registra um adapter. Chame na inicialização
useCapabilities() { capabilities, loading, refresh } — o que existe neste aparelho
usePayment({ adapterId? }) { pay, refund, abort, progress, result, error, busy }
usePrinter({ adapterId? }) { print, status, checkStatus, error, busy }
useScanner({ adapterId? }) { scan, value, error, busy }
resolve(capability, adapterId?) Acesso imperativo, sem React
PosError / isPosError Erro normalizado
renderColumns(cells, widths?, aligns?, total?) Colunas monoespacadas, útil fora do pacote também

adapterId só é necessário quando dois adapters oferecem a mesma capability — por exemplo impressora do PagBank e do Sunmi no mesmo aparelho.

Adapters

Fabricante Status Peer
PagBank / PagSeguro ✅ v1 @lucasmaffei/react-native-plugpag
Sunmi ✅ v1 @mitsuharu/react-native-sunmi-printer-library
Stone 🙋 quer? manda PR
Gertec 🙋 quer? manda PR
Elgin 🙋 quer? manda PR

Não preciso ter o seu hardware para aceitar o seu adapter. O contrato é executável: o pacote exporta uma suíte de conformidade que o seu adapter tem que passar. Ver ADAPTERS.md.

Estado do projeto

0.1.0, e vale ser honesto sobre o que isso significa:

  • O núcleo é TypeScript puro, com 130 testes e ~91% de cobertura, incluindo os adapters com os SDKs nativos simulados.
  • A validação em hardware físico ainda não foi feita. Os adapters foram escritos a partir da API pública de cada SDK e da experiência de três apps de POS em produção, mas o v1 sai antes da migração desses apps.

Se você rodar em terminal de verdade, abra uma issue contando o que funcionou e o que não — é o feedback mais valioso para este pacote agora.

Licença

MIT © Lucas Maffei

About

Camada unificada de POS para terminais brasileiros em React Native: pagamento, impressao termica e leitura de codigo, com adapters para PagBank/PlugPag e Sunmi.

Topics

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages