@fayz-ai/plugin-financial 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,6 +29,7 @@ export declare const MIGRATION_027_O_VALE_PRESENTE_NASCE_EM_LOTE_E_E_UM_PASSIVO
29
29
  export declare const MIGRATION_028_O_CARTAO_TEM_COR = "-- 028_o_cartao_tem_cor.sql\n--\n-- Quem tem quatro cart\u00F5es n\u00E3o os distingue pelo nome que digitou seis meses\n-- atr\u00E1s: distingue pela COR e pelos \u00FAltimos d\u00EDgitos, que \u00E9 como o cart\u00E3o est\u00E1\n-- na carteira. Uma tela de despesa que s\u00F3 diz \"Cart\u00E3o Empresarial\" obriga a\n-- pessoa a lembrar qual \u00E9 \u2014 e a errar de vez em quando, o que no fim do m\u00EAs \u00E9\n-- uma fatura conciliada contra o cart\u00E3o errado.\n--\n-- A cor \u00E9 do CADASTRO da conta, n\u00E3o derivada do id: derivar d\u00E1 cores est\u00E1veis e\n-- sem sentido (o roxo do Nubank n\u00E3o sai de um hash), e o dono quer poder pintar\n-- o cart\u00E3o como ele \u00E9 de verdade.\n--\n-- `color` \u00E9 texto livre e n\u00E3o um enum: \u00E9 um valor de CSS que a tela pinta. Um\n-- enum aqui obrigaria uma migration por cor nova, e a paleta \u00E9 escolha de quem\n-- desenha, n\u00E3o do banco. NULL \u00E9 resposta leg\u00EDtima \u2014 cart\u00E3o sem cor \u00E9 cart\u00E3o\n-- sem cor, e a tela usa o cinza padr\u00E3o em vez de inventar uma.\nALTER TABLE public.plg_financial_accounts\n ADD COLUMN IF NOT EXISTS color text;\n\nCOMMENT ON COLUMN public.plg_financial_accounts.color IS\n 'A cor com que o cart\u00E3o aparece na tela \u2014 \u00E9 assim que quem tem quatro cart\u00F5es sabe qual \u00E9. Texto (valor CSS), nulo quando n\u00E3o escolheram (028).';\n";
30
30
  export declare const MIGRATION_029_THE_KIOSK_SALE_IS_A_SALE_TOO = "-- ---------------------------------------------------------------------------\n-- 029_the_kiosk_sale_is_a_sale_too.sql\n--\n-- Um pedido fechado levanta seu receb\u00EDvel \u2014 n\u00E3o s\u00F3 o do sal\u00E3o e o da agenda.\n--\n-- O gate da 001 nomeava s\u00F3 `dine_in`; a 005 acrescentou `appointment` e\n-- `service_order`. Nenhuma das tr\u00EAs cobre o que o quiosque e a entrega fazem:\n-- um `takeout` fechado no totem ia para `completed` sem nada atr\u00E1s dele \u2014\n-- dinheiro cobrado na maquininha e nenhuma conta a receber nos livros. O mesmo\n-- valia para `delivery` e para a venda de balc\u00E3o do PDV.\n--\n-- ESTA MIGRATION \u00C9 UMA UNI\u00C3O, N\u00C3O UMA TROCA. Ela nasceu numa branch que s\u00F3\n-- conhecia o gate da 001 e, escrita como estava, teria removido `appointment`\n-- e `service_order` \u2014 desfazendo a 005 sem ru\u00EDdo, porque o gatilho engole a\n-- falha num WARNING e o pedido fecha calado. As seis esp\u00E9cies convivem: as\n-- tr\u00EAs da 001/005 mais `takeout`, `delivery` e `sale`.\n--\n-- SOBRE `sale`, que a 005 recusou de prop\u00F3sito (\"a loja fatura no checkout,\n-- pela extens\u00E3o dela\"): a recusa continua valendo para a loja e nada muda para\n-- ela. O pedido de loja NASCE fechado, e este gatilho \u00E9 `AFTER UPDATE OF\n-- status` \u2014 um pedido que j\u00E1 entra `completed` nunca o dispara. Quem `sale`\n-- alcan\u00E7a aqui \u00E9 a venda de balc\u00E3o do PDV, que abre e depois fecha. E se as\n-- duas portas se cruzarem, `order_raise_receivable` devolve a fatura que j\u00E1\n-- existe em vez de emitir a segunda.\n--\n-- A lista sai daqui e vira UMA fun\u00E7\u00E3o, porque ela tem dois leitores que n\u00E3o\n-- podem discordar: este gatilho, que decide quando levantar, e\n-- `v_orders_sem_invoice` (030), que audita quem fechou sem levantar. Se os dois\n-- guardassem a pr\u00F3pria c\u00F3pia, a que audita poderia ficar cega justamente para a\n-- esp\u00E9cie que a outra esqueceu \u2014 e foi exatamente essa cegueira que deixou o\n-- buraco do quiosque passar despercebido.\n--\n-- CUIDADO ao editar `order_raise_receivable` (010): recriar este gatilho junto\n-- com ela desfaz o alargamento, e a falha n\u00E3o aparece em lugar nenhum. Esse\n-- sil\u00EAncio \u00E9 de prop\u00F3sito (ver 001: o gar\u00E7om tem de conseguir fechar a mesa), e\n-- s\u00F3 \u00E9 seguro porque a 030 enxerga o estrago depois.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\n-- IMMUTABLE: \u00E9 uma constante com nome. O planejador dobra a chamada no plano,\n-- ent\u00E3o us\u00E1-la no WHERE de uma view n\u00E3o custa nada por linha.\nCREATE OR REPLACE FUNCTION public.order_selling_kinds()\nRETURNS text[]\nLANGUAGE sql\nIMMUTABLE\nPARALLEL SAFE\nAS $function$\n SELECT ARRAY['dine_in', 'takeout', 'delivery', 'sale', 'appointment', 'service_order']::text[];\n$function$;\n\nCOMMENT ON FUNCTION public.order_selling_kinds() IS\n 'As especies de pedido cuja CONCLUSAO levanta o recebivel (gatilho orders_raise_receivable_on_close, 001/005/029) e cuja conclusao sem levantar e um defeito (v_orders_sem_invoice, 030). Uma lista so, para que o gatilho e a auditoria nao possam discordar. `sale` esta dentro pela venda de balcao do PDV; o pedido de loja nasce fechado e nunca dispara um AFTER UPDATE.';\n\nREVOKE ALL ON FUNCTION public.order_selling_kinds() FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.order_selling_kinds() TO authenticated, service_role;\n\nCREATE OR REPLACE FUNCTION public.trg_order_raise_receivable_on_close()\nRETURNS trigger\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path = ''\nAS $function$\nBEGIN\n IF NEW.kind = ANY (public.order_selling_kinds())\n AND NEW.status = 'completed'\n AND coalesce(OLD.status, '') IS DISTINCT FROM 'completed' THEN\n -- Nunca deixa o fechamento falhar por causa da escritura\u00E7\u00E3o (001).\n BEGIN\n PERFORM public.order_raise_receivable(NEW.id);\n EXCEPTION WHEN OTHERS THEN\n RAISE WARNING 'order_raise_receivable falhou para o pedido %: %', NEW.id, SQLERRM;\n END;\n END IF;\n RETURN NEW;\nEND $function$;\n\nCOMMENT ON FUNCTION public.trg_order_raise_receivable_on_close() IS\n 'A comanda, o atendimento, a ordem de servico, o balcao, o quiosque e a entrega levantam o recebivel ao concluir (001, 005, 029). A lista vive em order_selling_kinds().';\n\nDROP TRIGGER IF EXISTS orders_raise_receivable_on_close ON public.orders;\nCREATE TRIGGER orders_raise_receivable_on_close\n AFTER UPDATE OF status ON public.orders\n FOR EACH ROW EXECUTE FUNCTION public.trg_order_raise_receivable_on_close();\n\n-- \u2500\u2500 o que j\u00E1 fechou pelas esp\u00E9cies novas e nunca foi faturado \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n--\n-- S\u00F3 as tr\u00EAs que este arquivo acrescenta: a 005 j\u00E1 varreu `appointment` e\n-- `service_order`, e `dine_in` nunca esteve fora do gate.\nDO $$\nDECLARE r record; v_n integer := 0;\nBEGIN\n FOR r IN\n SELECT o.id FROM public.orders o\n WHERE o.kind IN ('takeout', 'delivery', 'sale')\n AND o.status = 'completed'\n AND coalesce(o.total, 0) > 0\n AND NOT EXISTS (SELECT 1 FROM public.plg_financial_invoices f\n WHERE f.order_id = o.id AND f.cancelled_at IS NULL)\n LOOP\n BEGIN\n PERFORM public.order_raise_receivable(r.id);\n v_n := v_n + 1;\n EXCEPTION WHEN OTHERS THEN\n RAISE WARNING 'backfill 029: order_raise_receivable falhou para %: %', r.id, SQLERRM;\n END;\n END LOOP;\n IF v_n > 0 THEN\n RAISE NOTICE '029: % venda(s) de balcao/quiosque/entrega faturadas com atraso', v_n;\n END IF;\nEND $$;\n";
31
31
  export declare const MIGRATION_030_THE_CENSUS_CAN_SEE_THE_KIOSK = "-- ---------------------------------------------------------------------------\n-- 030_the_census_can_see_the_kiosk.sql\n--\n-- O censo enxerga as esp\u00E9cies que realmente vendem.\n--\n-- `v_orders_sem_invoice` responde \"quais pedidos fecharam sem levantar\n-- receb\u00EDvel\". A lista dela era `sale, purchase, course` \u2014 e essas tr\u00EAs n\u00E3o\n-- incluem NENHUMA das que o caixa, o quiosque e a entrega usam de verdade.\n-- Ent\u00E3o a view voltava zero linha para um pool com o defeito dentro, e zero\n-- linha l\u00EA como \"tudo certo\", n\u00E3o como \"n\u00E3o estou olhando\".\n--\n-- Isso importa mais que um furo de relat\u00F3rio por causa da escolha embutida no\n-- gatilho da 001: ele engole a falha num RAISE WARNING de prop\u00F3sito, para que a\n-- conta sempre feche com o cliente na frente. Essa escolha est\u00E1 certa \u2014 recusar\n-- o fechamento prenderia o cliente no sal\u00E3o \u2014, mas ela s\u00F3 \u00E9 SEGURA se algu\u00E9m\n-- rio abaixo tornar o sil\u00EAncio vis\u00EDvel. Esta view \u00E9 esse algu\u00E9m, e era cega\n-- exatamente para o caso que aconteceu: um `takeout` do totem que fechou sem\n-- fatura porque o gate ainda nomeava s\u00F3 `dine_in`.\n--\n-- A lista de esp\u00E9cies vem de `public.order_selling_kinds()` (029), a MESMA que\n-- o gatilho consulta para decidir quando levantar. \u00C9 o ponto todo: quem audita\n-- n\u00E3o pode ter uma c\u00F3pia pr\u00F3pria da regra que audita. Com a uni\u00E3o da 029 ela\n-- carrega tamb\u00E9m `appointment` e `service_order` \u2014 e \u00E9 o que se quer: a 005\n-- passou a faturar os dois ao concluir e fez o backfill, ent\u00E3o um atendimento\n-- conclu\u00EDdo sem fatura deixou de ser leg\u00EDtimo e passou a ser exatamente o tipo\n-- de sil\u00EAncio que esta view existe para mostrar.\n--\n-- `purchase` e `course` continuam: s\u00E3o documentos que tamb\u00E9m deveriam ter\n-- fatura, s\u00F3 n\u00E3o passam pelo gatilho de fechamento. A view alarga, n\u00E3o troca.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE VIEW public.v_orders_sem_invoice\nWITH (security_invoker = true) AS\nSELECT o.id AS order_id, o.tenant_id, o.unit_id, o.kind, o.channel, o.status,\n o.total, o.created_at\n FROM public.orders o\n WHERE (o.kind = ANY (public.order_selling_kinds()) OR o.kind IN ('purchase', 'course'))\n -- Um pedido ainda aberto n\u00E3o \u00E9 buraco: ele \u00E9 faturado quando fecha. O que\n -- n\u00E3o \u00E9 leg\u00EDtimo \u00E9 o que CONCLUIU e n\u00E3o levantou nada \u2014 a mesma distin\u00E7\u00E3o\n -- que o PRD 06 faz para o atendimento.\n AND o.status IN ('completed', 'invoiced', 'paid')\n AND NOT EXISTS (\n SELECT 1 FROM public.plg_financial_invoices f\n WHERE f.order_id = o.id AND f.cancelled_at IS NULL);\n\nCOMMENT ON VIEW public.v_orders_sem_invoice IS\n 'Pedidos que FECHARAM e nao produziram fatura (aceite do PRD 02/04). Vazio e a barra. As especies vem de order_selling_kinds(), a mesma lista que o gatilho de fechamento consulta, mais purchase e course. Um pedido ainda aberto fica de fora: ele e faturado quando fecha.';\n\nGRANT SELECT ON public.v_orders_sem_invoice TO authenticated, service_role;\n";
32
+ export declare const MIGRATION_031_THE_BANK_LINE_IS_EVIDENCE_NOT_A_SECOND_PAYMENT = "-- A bank statement line is evidence of cash movement until reconciliation.\n-- If matched, the app-native payment remains the sole economic event. If the\n-- user accepts the line without a match, that line becomes the economic event.\nCREATE OR REPLACE VIEW public.v_financial_cash_movements\nWITH (security_invoker = true) AS\nSELECT movement.*\n FROM public.plg_financial_movements movement\n LEFT JOIN public.plg_financial_movements reversed\n ON reversed.id = movement.reverses_id\n WHERE CASE\n -- A reversal has exactly the economic nature of the row it reverses. This\n -- keeps provider corrections neutral both for matched evidence and for an\n -- imported line that had previously been accepted as standalone.\n WHEN reversed.id IS NOT NULL THEN\n reversed.external_source IS NULL\n OR (reversed.reconciled_at IS NOT NULL AND reversed.matched_movement_id IS NULL)\n ELSE\n movement.external_source IS NULL\n OR (movement.reconciled_at IS NOT NULL AND movement.matched_movement_id IS NULL)\n END;\n\nCOMMENT ON VIEW public.v_financial_cash_movements IS\n 'Economic cash events. Native movements always count; imported statement lines count only after standalone acceptance, never when matched to a native movement. Reversals inherit the economic nature of the row they reverse.';\n\nGRANT SELECT ON public.v_financial_cash_movements TO authenticated, service_role;\n\nCREATE OR REPLACE VIEW public.v_financial_account_balances\nWITH (security_invoker = true) AS\nWITH debits AS (\n SELECT movement.debit_account_id AS account_id,\n sum(movement.amount) AS total,\n count(*) AS n\n FROM public.v_financial_cash_movements movement\n WHERE movement.status <> 'cancelled'\n AND movement.debit_account_id IS NOT NULL\n AND movement.movement_kind IN ('payment', 'transfer')\n GROUP BY movement.debit_account_id\n), credits AS (\n SELECT movement.credit_account_id AS account_id,\n sum(movement.amount) AS total,\n count(*) AS n\n FROM public.v_financial_cash_movements movement\n WHERE movement.status <> 'cancelled'\n AND movement.credit_account_id IS NOT NULL\n AND movement.movement_kind IN ('payment', 'transfer')\n GROUP BY movement.credit_account_id\n)\nSELECT account.id AS account_id,\n account.tenant_id,\n account.unit_id,\n account.kind,\n account.code,\n account.name,\n account.person_id,\n account.is_active,\n account.account_type,\n account.bank_name,\n account.agency_number,\n account.account_number,\n account.metadata,\n coalesce(debits.total, 0)::numeric(14,2) AS debit_total,\n coalesce(credits.total, 0)::numeric(14,2) AS credit_total,\n (coalesce(credits.total, 0) - coalesce(debits.total, 0))::numeric(14,2) AS net_credit,\n CASE\n WHEN account.kind IN ('bank', 'cash_physical', 'cash_session', 'card_receivable_credit', 'card_receivable_debit')\n THEN (coalesce(debits.total, 0) - coalesce(credits.total, 0))::numeric(14,2)\n ELSE (coalesce(credits.total, 0) - coalesce(debits.total, 0))::numeric(14,2)\n END AS balance,\n (coalesce(debits.n, 0) + coalesce(credits.n, 0))::integer AS movement_count,\n account.created_at,\n account.updated_at\n FROM public.plg_financial_accounts account\n LEFT JOIN debits ON debits.account_id = account.id\n LEFT JOIN credits ON credits.account_id = account.id;\n\nCOMMENT ON VIEW public.v_financial_account_balances IS\n 'Balances from economic cash events; matched bank evidence never duplicates its app-native payment.';\n\nGRANT SELECT ON public.v_financial_account_balances TO authenticated, service_role;\n";
32
33
  export declare const MIGRATIONS: Array<{
33
34
  id: string;
34
35
  sql: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,gu5QAm/HlC,CAAA;AAED,eAAO,MAAM,6DAA6D,4/NA2IzE,CAAA;AAED,eAAO,MAAM,0DAA0D,s8MA6GtE,CAAA;AAED,eAAO,MAAM,8CAA8C,2kSAiJ1D,CAAA;AAED,eAAO,MAAM,wCAAwC,6mRAmLpD,CAAA;AAED,eAAO,MAAM,qDAAqD,0tIAiFjE,CAAA;AAED,eAAO,MAAM,gEAAgE,0xjBAiU5E,CAAA;AAED,eAAO,MAAM,8DAA8D,mmgBA2Q1E,CAAA;AAED,eAAO,MAAM,+DAA+D,shwBAqX3E,CAAA;AAED,eAAO,MAAM,uDAAuD,ik2BAydnE,CAAA;AAED,eAAO,MAAM,+DAA+D,8iXAiR3E,CAAA;AAED,eAAO,MAAM,0DAA0D,qvRA6JtE,CAAA;AAED,eAAO,MAAM,wDAAwD,q3QAuKpE,CAAA;AAED,eAAO,MAAM,gEAAgE,0juBA2Y5E,CAAA;AAED,eAAO,MAAM,kDAAkD,60WAyN9D,CAAA;AAED,eAAO,MAAM,yCAAyC,u6OAgJrD,CAAA;AAED,eAAO,MAAM,4CAA4C,87PAwJxD,CAAA;AAED,eAAO,MAAM,iDAAiD,+3LAwH7D,CAAA;AAED,eAAO,MAAM,iDAAiD,o3GAmE7D,CAAA;AAED,eAAO,MAAM,yCAAyC,k0JAqGrD,CAAA;AAED,eAAO,MAAM,yDAAyD,s1CAsBrE,CAAA;AAED,eAAO,MAAM,yCAAyC,ymOAoIrD,CAAA;AAED,eAAO,MAAM,iDAAiD,g+MA0H7D,CAAA;AAED,eAAO,MAAM,6CAA6C,m1MAgIzD,CAAA;AAED,eAAO,MAAM,2CAA2C,+oMA+HvD,CAAA;AAED,eAAO,MAAM,4CAA4C,8rVA+LxD,CAAA;AAED,eAAO,MAAM,mDAAmD,qpMA4H/D,CAAA;AAED,eAAO,MAAM,0DAA0D,mshBAuStE,CAAA;AAED,eAAO,MAAM,8BAA8B,k4CAqB1C,CAAA;AAED,eAAO,MAAM,0CAA0C,smLA+GtD,CAAA;AAED,eAAO,MAAM,0CAA0C,sqGAiDtD,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAgCzD,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,gu5QAm/HlC,CAAA;AAED,eAAO,MAAM,6DAA6D,4/NA2IzE,CAAA;AAED,eAAO,MAAM,0DAA0D,s8MA6GtE,CAAA;AAED,eAAO,MAAM,8CAA8C,2kSAiJ1D,CAAA;AAED,eAAO,MAAM,wCAAwC,6mRAmLpD,CAAA;AAED,eAAO,MAAM,qDAAqD,0tIAiFjE,CAAA;AAED,eAAO,MAAM,gEAAgE,0xjBAiU5E,CAAA;AAED,eAAO,MAAM,8DAA8D,mmgBA2Q1E,CAAA;AAED,eAAO,MAAM,+DAA+D,shwBAqX3E,CAAA;AAED,eAAO,MAAM,uDAAuD,ik2BAydnE,CAAA;AAED,eAAO,MAAM,+DAA+D,8iXAiR3E,CAAA;AAED,eAAO,MAAM,0DAA0D,qvRA6JtE,CAAA;AAED,eAAO,MAAM,wDAAwD,q3QAuKpE,CAAA;AAED,eAAO,MAAM,gEAAgE,0juBA2Y5E,CAAA;AAED,eAAO,MAAM,kDAAkD,60WAyN9D,CAAA;AAED,eAAO,MAAM,yCAAyC,u6OAgJrD,CAAA;AAED,eAAO,MAAM,4CAA4C,87PAwJxD,CAAA;AAED,eAAO,MAAM,iDAAiD,+3LAwH7D,CAAA;AAED,eAAO,MAAM,iDAAiD,o3GAmE7D,CAAA;AAED,eAAO,MAAM,yCAAyC,k0JAqGrD,CAAA;AAED,eAAO,MAAM,yDAAyD,s1CAsBrE,CAAA;AAED,eAAO,MAAM,yCAAyC,ymOAoIrD,CAAA;AAED,eAAO,MAAM,iDAAiD,g+MA0H7D,CAAA;AAED,eAAO,MAAM,6CAA6C,m1MAgIzD,CAAA;AAED,eAAO,MAAM,2CAA2C,+oMA+HvD,CAAA;AAED,eAAO,MAAM,4CAA4C,8rVA+LxD,CAAA;AAED,eAAO,MAAM,mDAAmD,qpMA4H/D,CAAA;AAED,eAAO,MAAM,0DAA0D,mshBAuStE,CAAA;AAED,eAAO,MAAM,8BAA8B,k4CAqB1C,CAAA;AAED,eAAO,MAAM,0CAA0C,smLA+GtD,CAAA;AAED,eAAO,MAAM,0CAA0C,sqGAiDtD,CAAA;AAED,eAAO,MAAM,4DAA4D,ipHA+ExE,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAiCzD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"NotasFiscaisView.d.ts","sourceRoot":"","sources":["../../src/views/NotasFiscaisView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAA;AA0B/D,wBAAgB,gBAAgB,sBAwJ/B"}
1
+ {"version":3,"file":"NotasFiscaisView.d.ts","sourceRoot":"","sources":["../../src/views/NotasFiscaisView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAA;AA0B/D,wBAAgB,gBAAgB,sBA6M/B"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "status": "beta",
5
5
  "dependencies": []
6
6
  },
7
- "version": "0.13.1",
7
+ "version": "0.14.0",
8
8
  "description": "Fayz SDK — plugin-financial plugin",
9
9
  "type": "module",
10
10
  "sideEffects": false,