@fayz-ai/plugin-fiscal-br 0.3.5 → 0.3.7
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.
- package/dist/data/inbox.d.ts +10 -0
- package/dist/data/inbox.d.ts.map +1 -1
- package/dist/index.js +529 -237
- package/dist/index.js.map +1 -1
- package/dist/views/InboundNotesPage.d.ts.map +1 -1
- package/dist/views/InboundNotesView.d.ts.map +1 -1
- package/dist/views/NoteReconcileView.d.ts.map +1 -1
- package/package.json +6 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connectors/plugnotas.ts","../src/migrations/index.ts","../src/data/registries.ts","../src/lib/nfe-xml.ts","../src/data/inbox.ts","../src/views/InboundNotesView.tsx","../src/types.ts","../src/views/NoteReconcileView.tsx","../src/views/ManifestView.tsx","../src/views/InboundNotesPage.tsx","../src/lib/financial-provider.ts","../src/views/GapScreens.tsx","../src/views/inventoryView.tsx","../src/index.ts"],"names":["digits","money","day","useState","useCallback","useEffect","useMemo","jsxs","jsx","Skeleton","Card","Button","Trash2","Loader2","Hint","ListFilterBar"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA6jB/B,IAAM,0DAAA,GAA6D,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAqMnE,IAAM,+CAAA,GAAkD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA2WxD,IAAM,0CAAA,GAA6C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA;AAkPnD,IAAM,8CAAA,GAAiD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA;AAwBvD,IAAM,2CAAA,GAA8C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA+MpD,IAAM,yCAAA,GAA4C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAoBlD,IAAM,oDAAA,GAAuD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA;AAiC7D,IAAM,yDAAA,GAA4D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AA4NlE,IAAM,gEAAA,GAAmE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAsiBzE,IAAM,gEAAA,GAAmE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","file":"index.js","sourcesContent":["import type React from 'react'\nimport {\n connectionSettings,\n connectionStatus,\n createConnectionStore,\n settingsStatus,\n type ConnectionConfig,\n type ConnectorDefinition,\n type ConnectorField,\n type ConnectorSetting,\n} from '@fayz-ai/core'\nimport type { PlugNotasConnectorClient, PlugNotasEnvironment, PlugNotasSetupState } from '../types'\n\nexport const PLUGNOTAS_CONNECTOR_ID = 'plugnotas'\n\nconst PLUGNOTAS_MARK = \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230F766E'/%3E%3Cpath d='M10 7h12v18l-2-1.5-2 1.5-2-1.5-2 1.5-2-1.5-2 1.5V7Z' fill='white'/%3E%3Cpath d='M13 12h6M13 16h6M13 20h4' stroke='%230F766E' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E\"\n\nexport const PLUGNOTAS_FIELDS = [\n {\n key: 'emitterCnpj',\n label: 'CNPJ do emitente',\n type: 'text',\n placeholder: '00.000.000/0000-00',\n },\n] as const satisfies readonly ConnectorField[]\n\nexport const PLUGNOTAS_SETTINGS = [{\n key: 'environment',\n label: 'Ambiente fiscal',\n description: 'Sandbox simula o emissor. Homologação envia para a SEFAZ sem valor fiscal.',\n type: 'select',\n options: [\n { value: 'sandbox', label: 'Sandbox simulado' },\n { value: 'homologation', label: 'Homologação SEFAZ' },\n ],\n requiredToOperate: true,\n defaultValue: 'sandbox',\n}] as const satisfies readonly ConnectorSetting[]\n\nconst INTERNAL_SETTINGS = [\n 'certificateReady',\n 'cscReady',\n 'providerEmitterId',\n 'certificateExpiresAt',\n 'certificateFingerprint',\n // Non-secret operational data written by the host's server-side setup flow.\n // Declaring these keys keeps the shared connection store authoritative while\n // credentials (API key, A1 bytes/password, CSC) remain outside public JSON.\n 'stateRegistration',\n 'corporateName',\n 'tradeName',\n 'email',\n 'taxRegime',\n 'address',\n 'series',\n 'paymentMethod',\n]\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nfunction digits(value: string): string {\n return value.replace(/\\D/g, '')\n}\n\nexport function isValidCnpj(value: string): boolean {\n const normalized = digits(value)\n if (!/^\\d{14}$/.test(normalized) || /^(\\d)\\1{13}$/.test(normalized)) return false\n const digit = (base: string, weights: number[]) => {\n const sum = weights.reduce((total, weight, index) => total + Number(base[index]) * weight, 0)\n const remainder = sum % 11\n return remainder < 2 ? 0 : 11 - remainder\n }\n const first = digit(normalized.slice(0, 12), [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n const second = digit(`${normalized.slice(0, 12)}${first}`, [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n return normalized.endsWith(`${first}${second}`)\n}\n\nfunction environment(value: unknown): PlugNotasEnvironment {\n if (value === undefined || value === null || value === '' || value === 'sandbox') return 'sandbox'\n if (value === 'homologation') return value\n throw new Error('Produção não está disponível neste conector preview.')\n}\n\nfunction store() {\n return createConnectionStore(PLUGNOTAS_CONNECTOR_ID, {\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n settingsKeys: INTERNAL_SETTINGS,\n })\n}\n\nfunction deriveStatus(connection: ConnectionConfig | null) {\n if (!connection?.active) return { connected: false }\n const readiness = settingsStatus([...PLUGNOTAS_SETTINGS], connection)\n const certificateReady = connection.settings.certificateReady === true\n const cscReady = connection.settings.cscReady === true\n const expiry = typeof connection.settings.certificateExpiresAt === 'string'\n ? Date.parse(connection.settings.certificateExpiresAt)\n : Number.NaN\n const daysUntilExpiry = Number.isFinite(expiry) ? Math.ceil((expiry - Date.now()) / DAY_MS) : null\n const expired = daysUntilExpiry !== null && daysUntilExpiry <= 0\n const expiringSoon = daysUntilExpiry !== null && daysUntilExpiry > 0 && daysUntilExpiry <= 30\n const missingSettings = [...new Set([\n ...(readiness.missingSettings ?? []),\n ...(!certificateReady || expired ? ['certificate'] : []),\n ...(!cscReady ? ['csc'] : []),\n ])]\n\n return {\n connected: true,\n needsSetup: missingSettings.length > 0,\n ...(missingSettings.length ? { missingSettings } : {}),\n detail: expired\n ? 'Certificado A1 vencido'\n : !certificateReady\n ? 'Envie o certificado A1 do emitente.'\n : !cscReady\n ? 'Confirme o CSC e o ID Token do emitente.'\n : connection.settings.environment === 'homologation'\n ? 'Emitente pronto em homologação'\n : 'Emitente pronto no sandbox',\n ...(expiringSoon\n ? { issues: [`O certificado A1 vence em ${daysUntilExpiry} dia${daysUntilExpiry === 1 ? '' : 's'}.`] }\n : {}),\n plane: 'sync' as const,\n }\n}\n\nexport interface CreatePlugNotasConnectorOptions {\n client?: PlugNotasConnectorClient\n SetupPanel?: React.ComponentType\n}\n\nexport function createPlugNotasConnector(options: CreatePlugNotasConnectorOptions = {}): ConnectorDefinition {\n const connectionStore = store()\n return {\n id: PLUGNOTAS_CONNECTOR_ID,\n // PlugBank and PlugNotas are different products from the same vendor. The\n // directory key names the product, otherwise one silently replaces the\n // other in the generated connector map.\n catalogSlug: 'plugnotas',\n hostPluginId: 'financial',\n name: 'PlugNotas · NFC-e',\n description: 'Emita NFC-e pela TecnoSpeed sem expor certificado, senha ou API key no navegador.',\n icon: 'ReceiptText',\n logoUrl: PLUGNOTAS_MARK,\n authKind: 'api-key',\n category: 'erp',\n direction: 'outbound',\n planes: ['sync'],\n docsUrl: 'https://docs.plugnotas.com.br/',\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n permissions: [{\n kind: 'data',\n resource: 'fiscal-document',\n actions: ['read', 'write'],\n reason: 'Enviar a NFC-e e reconciliar situação, chave de acesso e artefatos no Financeiro.',\n sensitive: true,\n }],\n invokedAt: [{\n key: 'financial.nfce.issue',\n label: 'Quando um operador confirma a emissão da NFC-e de um pedido concluído',\n plane: 'sync',\n trigger: 'manual',\n touches: ['fiscal-document'],\n }],\n howItSyncs: [\n 'A emissão cria primeiro um comando durável e só depois chama o provedor.',\n 'Webhook e recuperação consultiva convergem o mesmo comando, sem reenviar no escuro.',\n ],\n ...connectionStatus(PLUGNOTAS_CONNECTOR_ID, deriveStatus, { store }),\n ...connectionSettings(connectionStore),\n async testConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) return { ok: false, message: 'Informe um CNPJ válido.' }\n let selected: PlugNotasEnvironment\n try {\n selected = environment(values.environment)\n } catch (error) {\n return { ok: false, message: error instanceof Error ? error.message : 'Ambiente inválido.' }\n }\n return options.client?.testEmitter\n ? options.client.testEmitter({ emitterCnpj, environment: selected })\n : { ok: true }\n },\n async saveConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await connectionStore.save({\n active: true,\n displayName: `Emitente ${emitterCnpj.slice(-6)}`,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(values.environment),\n certificateReady: false,\n cscReady: false,\n },\n })\n },\n ...(options.client?.disconnectEmitter\n ? { disconnect: () => options.client!.disconnectEmitter!() }\n : {}),\n disconnectNote: 'As notas existentes permanecem no Financeiro; somente novas emissões são interrompidas.',\n ExtraPanel: options.SetupPanel,\n }\n}\n\n/** Persist only server-confirmed readiness and non-secret certificate metadata. */\nexport async function markPlugNotasEmitterReady(input: PlugNotasSetupState): Promise<void> {\n const emitterCnpj = digits(input.emitterCnpj)\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await store().save({\n active: true,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(input.environment),\n certificateReady: input.certificateReady,\n cscReady: input.cscReady,\n providerEmitterId: input.providerEmitterId,\n certificateExpiresAt: input.certificateExpiresAt,\n certificateFingerprint: input.certificateFingerprint,\n },\n })\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_preserve_terminal_results_and_recover_leases.sql, 002_a_nota_que_chega_tem_onde_esperar.sql, 003_a_caixa_de_entrada_atravessa.sql, 004_o_grupo_fiscal_do_v1_repete_nome.sql, 005_a_nota_emitida_e_um_documento.sql, 006_o_grupo_fiscal_ganha_o_rail.sql, 007_a_rls_do_documento_passa_a_ser_legivel.sql, 008_a_nota_recebida_guarda_a_decisao_de_entrada.sql, 009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez.sql, 010_a_data_de_emissao_e_instante_e_a_competencia_e_dia.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- Fiscal Brasil / PlugNotas baseline.\n--\n-- This addon does not create a second fiscal ledger. \\`plg_financial_nfe\\`\n-- remains the authoritative document owned by plugin-financial. The tables\n-- below describe delivery to an external issuer: durable commands, attempts,\n-- webhooks and emitter ownership.\n--\n-- The file is additive and idempotent because the current restaurant pool is\n-- live. Applying it is deliberately outside this draft PR.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_jobs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Logical reference to plugin-financial's fiscal ledger. Cross-plugin\n -- physical foreign keys are intentionally forbidden: installation and\n -- removal of this addon must never rewrite another plugin's schema.\n nota_id uuid NOT NULL,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE RESTRICT,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE RESTRICT,\n operation text NOT NULL CHECK (operation IN ('issue', 'cancel')),\n status text NOT NULL DEFAULT 'queued'\n CHECK (status IN ('queued', 'running', 'waiting', 'succeeded', 'failed', 'manual_review')),\n idempotency_key text NOT NULL,\n provider_document_id text,\n integration_id text,\n request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb,\n provider_response jsonb NOT NULL DEFAULT '{}'::jsonb,\n attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),\n next_attempt_at timestamptz,\n locked_until timestamptz,\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_jobs_recovery_idx\n ON public.plg_fiscalbr_nfce_jobs (status, next_attempt_at, locked_until)\n WHERE status IN ('queued', 'waiting');\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_events (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n nota_id uuid NOT NULL,\n job_id uuid REFERENCES public.plg_fiscalbr_nfce_jobs(id) ON DELETE SET NULL,\n event_type text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_events_document_idx\n ON public.plg_fiscalbr_nfce_events (tenant_id, nota_id, created_at DESC);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_webhook_receipts (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n provider text NOT NULL DEFAULT 'plugnotas',\n provider_event_id text NOT NULL,\n tenant_id uuid REFERENCES public.tenants(id) ON DELETE SET NULL,\n nota_id uuid,\n payload_sha256 text NOT NULL,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n processing_error text,\n UNIQUE (provider, provider_event_id)\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_emitter_ownership (\n emitter_cnpj text PRIMARY KEY CHECK (emitter_cnpj ~ '^[0-9]{14}$'),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE CASCADE,\n environment text NOT NULL CHECK (environment IN ('sandbox', 'homologation')),\n provider_emitter_id text,\n certificate_expires_at timestamptz,\n certificate_fingerprint text,\n csc_ready boolean NOT NULL DEFAULT false,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, connection_id)\n);\n\nALTER TABLE public.plg_fiscalbr_nfce_jobs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_nfce_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_webhook_receipts ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_emitter_ownership ENABLE ROW LEVEL SECURITY;\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs;\nCREATE POLICY plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events;\nCREATE POLICY plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership;\nCREATE POLICY plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nREVOKE ALL ON public.plg_fiscalbr_nfce_jobs FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_nfce_events FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_webhook_receipts FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_emitter_ownership FROM anon, authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_jobs TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_events TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_emitter_ownership TO authenticated;\nGRANT ALL ON public.plg_fiscalbr_nfce_jobs TO service_role;\nGRANT ALL ON public.plg_fiscalbr_nfce_events TO service_role;\nGRANT ALL ON public.plg_fiscalbr_webhook_receipts TO service_role;\nGRANT ALL ON public.plg_fiscalbr_emitter_ownership TO service_role;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_register_emitter(\n p_tenant_id uuid,\n p_connection_id uuid,\n p_emitter_cnpj text,\n p_environment text,\n p_provider_emitter_id text DEFAULT NULL,\n p_certificate_expires_at timestamptz DEFAULT NULL,\n p_certificate_fingerprint text DEFAULT NULL,\n p_csc_ready boolean DEFAULT false\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_cnpj text := regexp_replace(coalesce(p_emitter_cnpj, ''), '[^0-9]', '', 'g');\nBEGIN\n IF v_cnpj !~ '^[0-9]{14}$' THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: invalid CNPJ' USING ERRCODE = '22023';\n END IF;\n IF p_environment NOT IN ('sandbox', 'homologation') THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: production is not enabled' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.connections c\n WHERE c.id = p_connection_id\n AND c.tenant_id = p_tenant_id\n AND c.connector_id = 'plugnotas'\n AND c.active\n ) THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: active connection not found' USING ERRCODE = 'P0002';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_emitter_ownership\n (emitter_cnpj, tenant_id, connection_id, environment, provider_emitter_id,\n certificate_expires_at, certificate_fingerprint, csc_ready, updated_at)\n VALUES\n (v_cnpj, p_tenant_id, p_connection_id, p_environment, p_provider_emitter_id,\n p_certificate_expires_at, p_certificate_fingerprint, p_csc_ready, now())\n ON CONFLICT (emitter_cnpj) DO UPDATE SET\n tenant_id = EXCLUDED.tenant_id,\n connection_id = EXCLUDED.connection_id,\n environment = EXCLUDED.environment,\n provider_emitter_id = EXCLUDED.provider_emitter_id,\n certificate_expires_at = EXCLUDED.certificate_expires_at,\n certificate_fingerprint = EXCLUDED.certificate_fingerprint,\n csc_ready = EXCLUDED.csc_ready,\n updated_at = now()\n WHERE public.plg_fiscalbr_emitter_ownership.tenant_id = EXCLUDED.tenant_id;\n\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: CNPJ belongs to another tenant' USING ERRCODE = '23505';\n END IF;\n\n UPDATE public.connections\n SET provider_account_key = v_cnpj,\n settings = settings || jsonb_build_object(\n 'environment', p_environment,\n 'certificateReady', p_certificate_expires_at IS NOT NULL,\n 'certificateExpiresAt', p_certificate_expires_at,\n 'certificateFingerprint', p_certificate_fingerprint,\n 'providerEmitterId', p_provider_emitter_id,\n 'cscReady', p_csc_ready\n ),\n status = CASE WHEN p_certificate_expires_at IS NOT NULL AND p_csc_ready THEN 'connected' ELSE 'pending' END,\n updated_at = now()\n WHERE id = p_connection_id AND tenant_id = p_tenant_id;\n\n RETURN jsonb_build_object('emitterCnpj', v_cnpj, 'environment', p_environment);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_disconnect_emitter(\n p_tenant_id uuid,\n p_connection_id uuid\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n DELETE FROM public.plg_fiscalbr_emitter_ownership\n WHERE tenant_id = p_tenant_id AND connection_id = p_connection_id;\n UPDATE public.connections\n SET active = false, status = 'revoked', settings = '{}'::jsonb,\n provider_state = '{}'::jsonb, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_connection_id AND connector_id = 'plugnotas';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_create_nfce_draft_for_order(\n p_tenant_id uuid,\n p_order_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_order public.orders%ROWTYPE;\n v_nota_id uuid;\nBEGIN\n -- Serialize draft creation per tenant/order without adding a column or\n -- index to the financial plugin's table. The order itself remains the\n -- stable idempotency boundary for one NFC-e draft.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || p_order_id::text, 0));\n\n SELECT * INTO v_order FROM public.orders\n WHERE tenant_id = p_tenant_id AND id = p_order_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_order.status NOT IN ('completed', 'paid', 'invoiced') THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order is not closed' USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.items i WHERE i.tenant_id = p_tenant_id AND i.order_id = p_order_id) THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order has no items' USING ERRCODE = '23514';\n END IF;\n\n SELECT n.id INTO v_nota_id FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.order_id = p_order_id AND n.model = 'nfce'\n ORDER BY n.created_at DESC LIMIT 1;\n IF v_nota_id IS NOT NULL THEN RETURN v_nota_id; END IF;\n\n INSERT INTO public.plg_financial_nfe\n (tenant_id, unit_id, model, status, order_id, contact_id, total_amount,\n emissor, metadata)\n VALUES\n (p_tenant_id, v_order.unit_id, 'nfce', 'draft', p_order_id, v_order.party_id,\n coalesce(v_order.total, 0), 'plugnotas',\n jsonb_build_object('source', 'order', 'orderKind', v_order.kind, 'orderChannel', v_order.channel))\n RETURNING id INTO v_nota_id;\n RETURN v_nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_idempotency_key text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_snapshot jsonb;\nBEGIN\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.model <> 'nfce' OR v_nota.order_id IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order-backed NFC-e not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_nota.status NOT IN ('draft', 'error', 'processing') THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: invalid document status %', v_nota.status USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_fiscalbr_emitter_ownership e\n WHERE e.tenant_id = p_tenant_id AND e.connection_id = p_connection_id\n AND e.csc_ready AND e.certificate_expires_at > now()\n ) THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: emitter is not ready' USING ERRCODE = '23514';\n END IF;\n\n SELECT jsonb_build_object(\n 'nota', to_jsonb(v_nota),\n 'order', to_jsonb(o),\n 'items', coalesce((\n SELECT jsonb_agg(to_jsonb(i) ORDER BY i.sort_order, i.id)\n FROM public.items i\n WHERE i.tenant_id = p_tenant_id AND i.order_id = v_nota.order_id\n ), '[]'::jsonb),\n -- Product tax metadata must be frozen in the same transaction as the order\n -- lines. Looking products up in the Edge Function would let a retry emit\n -- with NCM/CFOP changed after the operator confirmed the document.\n 'products', coalesce((\n SELECT jsonb_agg(to_jsonb(p) ORDER BY p.id)\n FROM public.products p\n WHERE p.tenant_id = p_tenant_id\n AND p.id IN (\n SELECT i.product_id FROM public.items i\n WHERE i.tenant_id = p_tenant_id\n AND i.order_id = v_nota.order_id\n AND i.product_id IS NOT NULL\n )\n ), '[]'::jsonb)\n ) INTO v_snapshot\n FROM public.orders o\n WHERE o.tenant_id = p_tenant_id AND o.id = v_nota.order_id;\n\n IF jsonb_array_length(v_snapshot->'items') = 0 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order has no items' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, request_snapshot, next_attempt_at, updated_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'issue', 'queued',\n p_idempotency_key, v_snapshot, now(), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE\n SET updated_at = now()\n RETURNING * INTO v_job;\n\n UPDATE public.plg_financial_nfe\n SET status = 'processing', error_message = NULL,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job.id, 'jobStatus', v_job.status, 'operation', 'issue'\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, p_nota_id, v_job.id, 'issue.queued', '{}'::jsonb);\n RETURN jsonb_build_object('jobId', v_job.id, 'snapshot', v_job.request_snapshot, 'replayed', v_job.attempts > 0);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce_cancel(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_reason text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job_id uuid;\n v_reason text := btrim(coalesce(p_reason, ''));\nBEGIN\n IF char_length(v_reason) NOT BETWEEN 15 AND 255 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: reason must contain 15 to 255 characters' USING ERRCODE = '22023';\n END IF;\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.status <> 'issued' OR v_nota.access_key IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: authorized NFC-e not found' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, provider_document_id, integration_id,\n request_snapshot, next_attempt_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'cancel', 'queued',\n 'nfce-cancel:' || p_nota_id::text,\n v_nota.metadata #>> '{plugnotas,providerDocumentId}',\n v_nota.metadata #>> '{plugnotas,integrationId}',\n jsonb_build_object('reason', v_reason), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE SET\n provider_document_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.provider_document_id,\n EXCLUDED.provider_document_id\n ),\n integration_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.integration_id,\n EXCLUDED.integration_id\n ),\n updated_at = now()\n RETURNING id INTO v_job_id;\n\n UPDATE public.plg_financial_nfe\n SET metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job_id, 'jobStatus', 'queued', 'operation', 'cancel', 'cancellationPending', true\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n RETURN jsonb_build_object('jobId', v_job_id, 'reason', v_reason);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status = 'processing' THEN 'issued'\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = CASE\n WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting'\n END,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN p_status = 'processing' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', CASE WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded' WHEN p_status = 'error' THEN 'failed' ELSE 'waiting' END,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND p_status = 'processing'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n IF v_receipt_id IS NULL THEN RETURN jsonb_build_object('duplicate', true); END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = now(), processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now()\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_get_artifact_locator(\n p_tenant_id uuid,\n p_nota_id uuid\n) RETURNS jsonb\nLANGUAGE sql SECURITY DEFINER SET search_path = '' STABLE AS $$\n SELECT jsonb_build_object(\n 'notaId', n.id,\n 'status', n.status,\n 'providerDocumentId', n.metadata #>> '{plugnotas,providerDocumentId}',\n 'integrationId', n.metadata #>> '{plugnotas,integrationId}'\n )\n FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.id = p_nota_id\n AND n.status IN ('issued', 'cancelled');\n$$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n\nREVOKE ALL ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) FROM PUBLIC, anon, authenticated;\n\nGRANT EXECUTE ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) TO service_role;\n`\n\nexport const MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES = `-- Incremental recovery fix. Preserve 000_baseline.sql and its recorded checksum.\n-- Only existing fiscal functions change; no parallel ledger/schema or backfill.\n-- CREATE OR REPLACE retains the service-role-only ACL from the baseline.\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = CASE WHEN p_status = 'running'\n THEN greatest(coalesce(locked_until, now()), now() + interval '2 minutes') ELSE NULL END,\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id AND status <> 'succeeded';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\n v_existing_status text;\n v_job_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n -- Match prepare/cancel's lock order: document, then job.\n SELECT status INTO v_existing_status FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: document not found' USING ERRCODE = 'P0002';\n END IF;\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n\n -- Late polling must not regress a concluded document or an active cancellation.\n IF v_existing_status = 'cancelled'\n OR (v_job.operation = 'issue' AND v_existing_status = 'issued' AND p_status <> 'cancelled')\n OR (v_job.status = 'succeeded' AND p_status IN ('processing', 'error')) THEN\n -- Old/interrupted jobs may still be running after the document concluded.\n -- Settle their lease too, otherwise recovery would claim them forever.\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = 'succeeded', locked_until = NULL, next_attempt_at = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n RETURN v_job.nota_id;\n END IF;\n\n v_job_status := CASE\n WHEN p_status = 'cancelled' OR (v_job.operation = 'issue' AND p_status = 'issued') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting' END;\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status <> 'cancelled' THEN v_existing_status\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = v_job_status,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN v_job_status = 'waiting' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN v_document_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', v_job_status,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND v_job_status = 'waiting'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\n v_receipt public.plg_fiscalbr_webhook_receipts%ROWTYPE;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n SELECT * INTO v_receipt FROM public.plg_fiscalbr_webhook_receipts\n WHERE provider = 'plugnotas' AND provider_event_id = p_provider_event_id FOR UPDATE;\n v_receipt_id := v_receipt.id;\n IF v_receipt.payload_sha256 IS DISTINCT FROM p_payload_sha256 THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_webhook: conflicting event payload' USING ERRCODE = '22023';\n END IF;\n IF v_receipt.processed_at IS NOT NULL AND v_receipt.processing_error IS NULL THEN\n RETURN jsonb_build_object('duplicate', true, 'matched', true);\n END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = NULL, processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now(), processing_error = NULL\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting', 'running')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n`\n\nexport const MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR = `-- A nota que chega tem onde esperar.\n--\n-- O V1 recebe NF-e de fornecedor pela SEFAZ e guarda cada uma numa caixa de\n-- entrada antes de alguém decidir o que fazer com ela: manifestar, importar\n-- para o estoque, ou nada. Essa caixa não tinha destino no V2.\n--\n-- dfe_inbox 703 a nota recebida, com o XML inteiro\n-- dfe_inbox_items 3.215 o item da nota, com todo o tributo\n-- dfe_inbox_payments 739 a forma de pagamento declarada\n-- dfe_inbox_duplicatas 830 o vencimento da duplicata\n-- fiscal_groups 11 o grupo fiscal (CFOP, CST, alíquotas)\n--\n-- Os números somam os dois tenants: Espaço Facial e Pertinho do Céu. É o único\n-- domínio fiscal que os dois usam.\n--\n-- ── O XML é arquivo, e arquivo mora em public.documents ─────────────────────\n--\n-- \\`dfe_inbox.xml_content\\` é o XML inteiro numa coluna de texto, e\n-- \\`pdf_storage_path\\` aponta para o DANFE no storage do V1. Os dois são ARQUIVO,\n-- e o V2 já tem o arquétipo: \\`public.documents\\`, com kind, checksum, storage_*\n-- e a RLS de arquivo que uma coluna de texto nunca teria.\n--\n-- Então a extensão guarda um PONTEIRO — \\`document_id\\` — e os bytes vão para o\n-- arquétipo, pelo estágio de assets (\\`make mig-assets\\`), que é quem alcança\n-- object storage. Enquanto os bytes não chegam, \\`document_id\\` fica nulo e o\n-- caminho de origem fica em metadata: a linha é verdadeira nos dois momentos.\n--\n-- ── O tributo vem inteiro, e de propósito ───────────────────────────────────\n--\n-- 30 colunas de imposto por item (ICMS, ICMS-ST, PIS, COFINS, IPI, com base,\n-- alíquota e valor de cada). É muita coluna, e a tentação é jogar tudo num\n-- jsonb. Não: isto é documento fiscal recebido, e a pergunta que se faz dele é\n-- \"quanto de ICMS entrou neste mês\" — uma soma, sobre coluna, com índice. Um\n-- jsonb transformaria toda apuração numa varredura.\n--\n-- O que VAI para jsonb é o \\`raw_xml_item\\`, que já é jsonb na origem e existe\n-- para conferência, não para conta.\n--\n-- Idempotente.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_documents (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n -- O ponteiro para o arquétipo. Nulo enquanto os bytes não subiram — o\n -- caminho de origem fica em metadata até lá.\n document_id uuid,\n access_key text,\n nfe_number text,\n nfe_series text,\n nfe_model text,\n issue_date timestamp with time zone,\n received_at timestamp with time zone,\n status text DEFAULT 'received'::text NOT NULL,\n -- A manifestação do destinatário é outro eixo que o status: uma nota pode\n -- estar recebida e não manifestada, e é a manifestação que a SEFAZ cobra.\n manifestation_status text,\n manifested_at timestamp with time zone,\n manifestation_attempts integer DEFAULT 0 NOT NULL,\n manifestation_response jsonb,\n supplier_party_id uuid,\n supplier_cnpj text,\n supplier_name text,\n supplier_ie text,\n total_value numeric(14,2),\n total_products numeric(14,2),\n total_discount numeric(14,2),\n total_freight numeric(14,2),\n total_insurance numeric(14,2),\n total_other numeric(14,2),\n total_icms_base numeric(14,2),\n total_icms_value numeric(14,2),\n total_icms_st_base numeric(14,2),\n total_icms_st_value numeric(14,2),\n total_pis_value numeric(14,2),\n total_cofins_value numeric(14,2),\n total_ipi_value numeric(14,2),\n nfe_protocol text,\n nfe_authorized_at timestamp with time zone,\n carrier_name text,\n carrier_cnpj text,\n freight_mode_code text,\n additional_info text,\n reviewed_at timestamp with time zone,\n -- O que essa nota virou no estoque, quando virou. Nulo é nota recebida e\n -- não importada, que é a maioria.\n inventory_operation_id uuid,\n owner_id uuid,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_documents IS\n 'A NF-e de fornecedor recebida da SEFAZ, esperando manifestação ou importação. V1: dfe_inbox.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_documents.document_id IS\n 'V1: xml_content + pdf_storage_path. O XML e o DANFE são arquivo; os bytes moram em public.documents e aqui fica o ponteiro.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_items (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n item_number integer,\n supplier_product_code text,\n ean_barcode text,\n ean_taxable text,\n description text,\n ncm text,\n cest text,\n cfop text,\n unit_commercial text,\n unit_taxable text,\n quantity_commercial numeric(18,4),\n quantity_taxable numeric(18,4),\n unit_price_commercial numeric(18,6),\n unit_price_taxable numeric(18,6),\n total_price numeric(14,2),\n discount numeric(14,2),\n freight numeric(14,2),\n insurance numeric(14,2),\n other_expenses numeric(14,2),\n icms_cst text, icms_csosn text, icms_origin text,\n icms_base numeric(14,2), icms_rate numeric(9,4), icms_value numeric(14,2),\n icms_st_base numeric(14,2), icms_st_value numeric(14,2),\n pis_cst text, pis_base numeric(14,2), pis_rate numeric(9,4), pis_value numeric(14,2),\n cofins_cst text, cofins_base numeric(14,2), cofins_rate numeric(9,4), cofins_value numeric(14,2),\n ipi_cst text, ipi_rate numeric(9,4), ipi_value numeric(14,2),\n -- O produto do V2 que esta linha da nota representa. \\`reconciled\\` é a\n -- decisão de quem conferiu; o id é o resultado dela.\n product_id uuid,\n reconciled boolean DEFAULT false NOT NULL,\n raw_xml_item jsonb,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_items IS\n 'O item da NF-e recebida, com o tributo em coluna — a apuração soma coluna, não varre jsonb. V1: dfe_inbox_items.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_payments (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n payment_index integer,\n payment_indicator text,\n payment_type_code text,\n payment_type_label text,\n value numeric(14,2),\n change_given numeric(14,2),\n card_brand text,\n card_acquirer_cnpj text,\n card_auth_code text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_duplicates (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n duplicate_index integer,\n number text,\n due_date date,\n value numeric(14,2),\n -- O que essa duplicata virou no contas a pagar, se alguém a lançou.\n installment_id uuid,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_duplicates IS\n 'O vencimento declarado na NF-e recebida. Vira parcela do contas a pagar quando alguém lança a nota. V1: dfe_inbox_duplicatas.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_tax_groups (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n cfop text,\n csosn text,\n cst text,\n icms_origin text,\n icms_rate numeric(9,4),\n icms_bc_mode text,\n pis_situation text,\n pis_rate numeric(9,4),\n cofins_situation text,\n cofins_rate numeric(9,4),\n -- A reforma tributária já está no cadastro do V1 e vem junto: deixar de\n -- fora obrigaria a recadastrar tudo no dia em que IBS/CBS valerem.\n ibs_cbs_situation text,\n ibs_cbs_classification text,\n base_calculation_mode text,\n benefit_code text,\n cest text,\n poverty_fund_rate numeric(9,4),\n is_active boolean DEFAULT true NOT NULL,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_tax_groups IS\n 'O grupo fiscal: CFOP, CST/CSOSN e alíquotas que o produto herda na emissão. V1: fiscal_groups. Traz IBS/CBS porque o cadastro do V1 já os tem.';\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- As chaves, os índices e a cerca\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = ('public.' || t)::regclass AND contype = 'p') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I PRIMARY KEY (id)', t, t || '_pkey');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_id_id_key') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I UNIQUE (tenant_id, id)', t, t || '_tenant_id_id_key');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_fkey') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE', t, t || '_tenant_fkey');\n END IF;\n END LOOP;\nEND $$;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n -- O arquivo pode ser apagado sem levar a nota junto: a nota fiscal existe\n -- mesmo sem o XML à mão, e é ela que a SEFAZ conhece.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_document_fkey\n FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_supplier_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_supplier_fkey\n FOREIGN KEY (supplier_party_id) REFERENCES public.people(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_operation_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_operation_fkey\n FOREIGN KEY (inventory_operation_id) REFERENCES public.plg_inventory_operations(id) ON DELETE SET NULL;\n END IF;\n\n -- Item, pagamento e duplicata não existem fora da nota: CASCADE.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_product_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_payments_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_payments ADD CONSTRAINT plg_fiscalbr_inbox_payments_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_installment_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_installment_fkey\n FOREIGN KEY (installment_id) REFERENCES public.plg_financial_invoice_installments(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\n-- A chave de acesso é única por casa: a mesma nota chegando duas vezes da SEFAZ\n-- é a mesma nota, e é isso que impede a importação em dobro.\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_access_key_uidx\n ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, access_key)\n WHERE access_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_pending_idx\n ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, unit_id, issue_date DESC)\n WHERE inventory_operation_id IS NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_document_idx\n ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, inbox_document_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_product_idx\n ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, product_id) WHERE product_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_payments_document_idx\n ON public.plg_fiscalbr_inbox_payments USING btree (tenant_id, inbox_document_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_duplicates_document_idx\n ON public.plg_fiscalbr_inbox_duplicates USING btree (tenant_id, inbox_document_id);\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_uidx\n ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));\n\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', t || '_updated_at', t);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()', t || '_updated_at', t);\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- Quem enxerga\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Nota fiscal é do FINANCEIRO, e a permissão é a que ele já usa. A caixa de\n-- entrada não tem unidade nos filhos — eles herdam a da nota —, então o escopo\n-- de unidade vale só no documento; o resto é do tenant, e é a CASCADE da FK que\n-- garante que ninguém veja filho de nota alheia.\n-- RLS, uma a uma e por extenso. O laço adiante já liga tudo isto — mas ele liga\n-- por \\`EXECUTE format(...)\\`, e o portão que revisa plugin lê o ARQUIVO, não o\n-- banco: para ele, tabela com tenant_id e sem um ENABLE literal é tabela\n-- aberta. Uma garantia que o revisor não consegue ler é uma garantia que\n-- ninguém confere.\nALTER TABLE public.plg_fiscalbr_inbox_documents ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_items ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_tax_groups ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_payments ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_duplicates ENABLE ROW LEVEL SECURITY;\n\nDO $$\nDECLARE\n t text;\n doc boolean;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n doc := t = 'plg_fiscalbr_inbox_documents';\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', t);\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.%I TO authenticated', t);\n EXECUTE format('GRANT ALL ON TABLE public.%I TO service_role', t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_select', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (%s)\n AND (SELECT app.has_permission('financial.read', %s)))$f$,\n t || '_authz_select', t,\n CASE WHEN doc THEN format('unit_id IS NULL OR (SELECT app.has_unit(%I.unit_id))', t) ELSE 'true' END,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_write', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', %s)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', %s)))$f$,\n t || '_authz_write', t,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n END LOOP;\nEND $$;\n\nINSERT INTO public.scoped_resources (resource_table, unit_column, owner_column, shareable, default_visibility, label)\nVALUES ('plg_fiscalbr_inbox_documents', 'unit_id', 'owner_id', false, 'unit', 'Notas recebidas')\nON CONFLICT (resource_table) DO UPDATE\n SET unit_column = EXCLUDED.unit_column, default_visibility = EXCLUDED.default_visibility, label = EXCLUDED.label;\n`\n\nexport const MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA = `-- A caixa de entrada atravessa.\n--\n-- A 002 fez as cinco tabelas. Esta escreve o de-para. As cinco usam o writer\n-- genérico \\`by_shape\\` (spine 123): as colunas do destino foram desenhadas\n-- olhando a origem, então o que falta é dizer qual nome vira qual — não uma\n-- função de upsert por tabela.\n--\n-- ── O arquivo não vem por aqui ──────────────────────────────────────────────\n--\n-- \\`xml_content\\` guarda o XML inteiro e \\`pdf_storage_path\\` aponta para o DANFE.\n-- Os dois saem do de-para com \\`-\\`: arquivo atravessa pelo estágio de assets,\n-- que é quem alcança object storage, e vira linha de \\`public.documents\\`. O\n-- caminho de origem fica em metadata para o estágio achar.\n--\n-- ── O fornecedor fica para a costura ────────────────────────────────────────\n--\n-- \\`supplier_party_id\\` não é preenchido aqui. A origem guarda CNPJ e nome, não\n-- um id de contato, e casar CNPJ com \\`public.people\\` é uma decisão de\n-- identidade — a mesma que já pôs 438 clientes em quarentena. Fica nulo, com o\n-- CNPJ na coluna ao lado, e uma passada de costura resolve quando alguém\n-- decidir a regra.\n--\n-- Idempotente.\n\nSET LOCAL migration.allowlist_unlock = 'on';\n\nSELECT migration._allow(\n 'fiscal_groups', 'public.plg_fiscalbr_tax_groups', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_tax_groups'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'name', 'name',\n 'cfop', 'cfop',\n 'csosn', 'csosn',\n 'cst', 'cst',\n 'icms_origin', 'icms_origin',\n 'icms_rate', 'icms_rate',\n 'icms_modalidade_bc', 'icms_bc_mode',\n 'pis_situation', 'pis_situation',\n 'pis_rate', 'pis_rate',\n 'cofins_situation', 'cofins_situation',\n 'cofins_rate', 'cofins_rate',\n 'ibs_cbs_situation', 'ibs_cbs_situation',\n 'ibs_cbs_classification', 'ibs_cbs_classification',\n 'base_calculation_mode', 'base_calculation_mode',\n 'cbenef', 'benefit_code',\n 'cest', 'cest',\n 'poverty_fund_rate', 'poverty_fund_rate',\n 'active', 'is_active',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O grupo fiscal: CFOP, CST/CSOSN e alíquotas que o produto herda na emissão. '\n 'IBS/CBS vêm junto porque o cadastro do V1 já os tem — deixar de fora '\n 'obrigaria a recadastrar tudo no dia em que a reforma valer.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox', 'public.plg_fiscalbr_inbox_documents', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_documents'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'company_id', 'unit_id@companies',\n 'access_key', 'access_key',\n 'nfe_number', 'nfe_number',\n 'nfe_series', 'nfe_series',\n 'nfe_model', 'nfe_model',\n 'issue_date', 'issue_date',\n 'received_at', 'received_at',\n 'status', 'status',\n 'manifestation_status', 'manifestation_status',\n 'manifested_at', 'manifested_at',\n 'manifestation_attempts', 'manifestation_attempts',\n 'manifestation_response', 'manifestation_response',\n 'supplier_cnpj', 'supplier_cnpj',\n 'supplier_name', 'supplier_name',\n 'supplier_ie', 'supplier_ie',\n 'total_value', 'total_value',\n 'total_products', 'total_products',\n 'total_discount', 'total_discount',\n 'total_freight', 'total_freight',\n 'total_insurance', 'total_insurance',\n 'total_other', 'total_other',\n 'total_icms_base', 'total_icms_base',\n 'total_icms_value', 'total_icms_value',\n 'total_icms_st_base', 'total_icms_st_base',\n 'total_icms_st_value', 'total_icms_st_value',\n 'total_pis_value', 'total_pis_value',\n 'total_cofins_value', 'total_cofins_value',\n 'total_ipi_value', 'total_ipi_value',\n 'nfe_protocol', 'nfe_protocol') ||\n -- \\`jsonb_build_object\\` aceita no máximo 100 argumentos, e este de-para tem\n -- 59 pares. Dois objetos concatenados, e não uma tabela a menos.\n jsonb_build_object(\n 'nfe_authorized_at', 'nfe_authorized_at',\n 'carrier_name', 'carrier_name',\n 'carrier_cnpj', 'carrier_cnpj',\n 'freight_mode_code', 'freight_mode_code',\n 'additional_info', 'additional_info',\n 'reviewed_at', 'reviewed_at',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'reviewed_by', '-',\n 'xml_content', '-',\n 'pdf_storage_path', 'jsonb:fiscalbr.v1_pdf_path',\n 'pdf_fetched_at', 'jsonb:fiscalbr.v1_pdf_fetched_at',\n 'danfe_import_id', 'jsonb:fiscalbr.v1_danfe_import_ref',\n 'plugnotas_payload', 'jsonb:fiscalbr.v1_plugnotas_payload',\n 'plugnotas_received_at', 'jsonb:fiscalbr.v1_plugnotas_received_at',\n 'nfe_cnf', 'jsonb:fiscalbr.nfe.cnf',\n 'nfe_natureza_operacao', 'jsonb:fiscalbr.nfe.natureza_operacao',\n 'nfe_finalidade', 'jsonb:fiscalbr.nfe.finalidade',\n 'nfe_tipo_operacao', 'jsonb:fiscalbr.nfe.tipo_operacao',\n 'nfe_destination', 'jsonb:fiscalbr.nfe.destination',\n 'supplier_address', 'jsonb:fiscalbr.supplier.street',\n 'supplier_number', 'jsonb:fiscalbr.supplier.number',\n 'supplier_complement', 'jsonb:fiscalbr.supplier.complement',\n 'supplier_neighborhood', 'jsonb:fiscalbr.supplier.neighborhood',\n 'supplier_city', 'jsonb:fiscalbr.supplier.city',\n 'supplier_state', 'jsonb:fiscalbr.supplier.state',\n 'supplier_postal_code', 'jsonb:fiscalbr.supplier.postal_code',\n 'supplier_phone', 'jsonb:fiscalbr.supplier.phone',\n 'supplier_email', 'jsonb:fiscalbr.supplier.email',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'A NF-e de fornecedor recebida da SEFAZ. \\`xml_content\\` sai com \\`-\\`: arquivo '\n 'atravessa pelo estágio de assets e vira public.documents, e o caminho do '\n 'DANFE fica em metadata para o estágio achar. O endereço do fornecedor vai '\n 'para metadata porque o fornecedor é \\`public.people\\`, e duplicá-lo em coluna '\n 'daria duas respostas para \"onde ele fica\".'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_items', 'public.plg_fiscalbr_inbox_items', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_items'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'item_number', 'item_number',\n 'product_code_supplier', 'supplier_product_code',\n 'ean_barcode', 'ean_barcode',\n 'ean_trib', 'ean_taxable',\n 'description', 'description',\n 'ncm', 'ncm',\n 'cest', 'cest',\n 'cfop', 'cfop',\n 'unit_commercial', 'unit_commercial',\n 'unit_taxable', 'unit_taxable',\n 'quantity_commercial', 'quantity_commercial',\n 'quantity_taxable', 'quantity_taxable',\n 'unit_price_commercial', 'unit_price_commercial',\n 'unit_price_taxable', 'unit_price_taxable',\n 'total_price', 'total_price',\n 'discount', 'discount',\n 'freight', 'freight',\n 'insurance', 'insurance',\n 'other_expenses', 'other_expenses',\n 'icms_cst', 'icms_cst',\n 'icms_csosn', 'icms_csosn',\n 'icms_origin', 'icms_origin',\n 'icms_base', 'icms_base',\n 'icms_rate', 'icms_rate',\n 'icms_value', 'icms_value',\n 'icms_st_base', 'icms_st_base',\n 'icms_st_value', 'icms_st_value',\n 'pis_cst', 'pis_cst',\n 'pis_base', 'pis_base',\n 'pis_rate', 'pis_rate',\n 'pis_value', 'pis_value',\n 'cofins_cst', 'cofins_cst',\n 'cofins_base', 'cofins_base',\n 'cofins_rate', 'cofins_rate',\n 'cofins_value', 'cofins_value',\n 'ipi_cst', 'ipi_cst',\n 'ipi_rate', 'ipi_rate',\n 'ipi_value', 'ipi_value',\n 'linked_product_id', 'product_id@products',\n 'reconciled', 'reconciled',\n 'raw_xml_item', 'raw_xml_item',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O item da nota, com o tributo em COLUNA — a apuração soma coluna, não varre '\n 'jsonb. \\`raw_xml_item\\` é a exceção: já é jsonb na origem e serve para '\n 'conferência, não para conta.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_payments', 'public.plg_fiscalbr_inbox_payments', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_payments'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'payment_index', 'payment_index',\n 'indicador_pagamento', 'payment_indicator',\n 'tipo_pagamento_code', 'payment_type_code',\n 'tipo_pagamento_label', 'payment_type_label',\n 'value', 'value',\n 'troco', 'change_given',\n 'card_flag', 'card_brand',\n 'card_acquirer_cnpj', 'card_acquirer_cnpj',\n 'card_auth_code', 'card_auth_code',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'A forma de pagamento declarada na nota recebida.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_duplicatas', 'public.plg_fiscalbr_inbox_duplicates', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_duplicates'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'duplicata_index', 'duplicate_index',\n 'numero', 'number',\n 'vencimento', 'due_date',\n 'valor', 'value',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O vencimento declarado na nota. Vira parcela do contas a pagar quando alguém '\n 'lança a nota — \\`installment_id\\` fica nulo até lá, porque a parcela é '\n 'decisão de quem lança, não da SEFAZ.'\n);\n\nDELETE FROM migration.excluded_tables\n WHERE source_table IN ('dfe_inbox', 'dfe_inbox_items', 'dfe_inbox_payments',\n 'dfe_inbox_duplicatas', 'fiscal_groups');\n\nRESET migration.allowlist_unlock;\n`\n\nexport const MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME = `-- O grupo fiscal do V1 repete nome.\n--\n-- A 002 criou índice ÚNICO em \\`(tenant_id, lower(name))\\`. O V1 tem, no tenant\n-- 8, \"Bebidas Alcoólicas\", \"Bebidas Não Alcoólicas\" e \"Vinhos e Espumantes\"\n-- DUAS vezes cada — grupos fiscais diferentes com o mesmo rótulo, e o V1\n-- permite. Três das onze linhas foram para a quarentena por uma regra que eu\n-- inventei, não que a origem tenha.\n--\n-- O índice vira comum: serve para buscar, não para proibir. Quem quiser proibir\n-- decide isso na tela, com o dado já dentro — e sabendo quais três são.\n--\n-- Esta correção nasceu dentro de \\`financial/083\\` e mudou de arquivo: o\n-- financeiro roda ANTES do fiscal_br na corrente, e um arquivo do financeiro\n-- que mexe numa tabela do fiscal_br falha do zero com\n-- \\`relation \"public.plg_fiscalbr_tax_groups\" does not exist\\`. Cada plugin mexe\n-- na tabela que é dele.\n--\n-- Idempotente.\n\nDROP INDEX IF EXISTS public.plg_fiscalbr_tax_groups_name_uidx;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_idx\n ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));\n`\n\nexport const MIGRATION_005_A_NOTA_EMITIDA_E_UM_DOCUMENTO = `-- A nota emitida é um DOCUMENTO, e o documento já tem arquétipo.\n--\n-- O V1 do Pertinho do Céu emitiu 496 notas (todas NFC-e: 440 concluídas, 51\n-- rejeitadas, 5 com erro) e nenhuma delas tem onde morar no V2. O que existe\n-- hoje aqui é a caixa de ENTRADA (\\`plg_fiscalbr_inbox_*\\`, a nota que chega do\n-- fornecedor) e o JOB de saída (\\`plg_fiscalbr_nfce_jobs\\`, a tentativa de\n-- emitir). Falta o resultado: a nota que a casa emitiu, com chave, protocolo e\n-- XML.\n--\n-- ── Por que pendurar em \\`public.documents\\` e não numa tabela solta ─────────\n--\n-- Porque a pergunta que o operador faz não é \"quais notas fiscais existem\",\n-- é \"o que foi emitido sobre ESTE pedido\". Hoje a resposta está espalhada:\n-- o anexo do título está em \\`documents\\`, o formulário está em \\`documents\\`, a\n-- foto do ponto está em \\`documents\\` — e a nota fiscal ficaria de fora, sendo\n-- o documento mais documento de todos.\n--\n-- \\`documents\\` é o arquétipo: \\`kind\\` diz a espécie, \\`subject_type\\`/\\`subject_id\\`\n-- dizem sobre o quê, e o plugin pendura o que só ele entende numa extensão 1:1\n-- pela chave — exatamente como \\`plg_forms_documents\\` já faz. Esta migração\n-- segue esse padrão, não inventa outro.\n--\n-- ── O que entra e o que NÃO entra ─────────────────────────────────────────\n--\n-- ENTRA o artefato legal e a trilha:\n-- xml_content 113 de 496 preenchidos, 618 kB no total (5,6 kB cada).\n-- É a prova da emissão e não se regenera. Fica.\n-- os quatro payloads 108 kB para as 496 notas inteiras. É a conversa com a\n-- SEFAZ, e é ela que explica as 51 rejeições.\n-- pdf_storage_path 84 de 496. Vira \\`documents.storage_path\\` com\n-- \\`storage_provider = 'v1-pending'\\`, a mesma convenção\n-- que \\`upsert_document\\` usa: o REGISTRO chegou, os bytes\n-- ainda não.\n--\n-- NÃO entra nada que o V2 já saiba responder por conta própria, e a emissão\n-- nova do V2 continua nascendo por \\`plg_fiscalbr_nfce_jobs\\` — este arquivo é o\n-- destino do resultado, não um segundo caminho de emissão.\n--\n-- ── Os dois ponteiros da nota do V1, que não são o mesmo ──────────────────\n--\n-- fiscal_documents.order_id 496 de 496 — a COMANDA (\\`table_orders\\`)\n-- fiscal_documents.invoice_id 118 de 496 — a VENDA (\\`invoices\\`)\n--\n-- Os dois chegam em \\`public.orders\\` no V2, e às vezes na MESMA linha (a\n-- comanda que virou nota adota a venda). Guardar os dois na mesma coluna\n-- perderia justamente a distinção: \\`order_id\\` na extensão é a comanda; a venda\n-- vai para \\`plg_fiscalbr_document_orders\\`, que é N:N porque uma nota pode\n-- juntar várias (511 vínculos para 496 notas).\n--\n-- Idempotente.\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. A espécie entra no vocabulário\n-- ═══════════════════════════════════════════════════════════════════════════\n-- \\`migration.upsert_document\\` RECUSA espécie que não esteja aqui, e faz certo:\n-- é o registro que impede \\`kind\\` de virar campo livre.\n\nINSERT INTO public.document_kinds (kind, plugin, description, statuses, status)\nVALUES ('fiscal_document', 'fiscal_br',\n 'A nota fiscal que a casa EMITIU (NFC-e, NF-e, NFS-e), com chave, protocolo e XML',\n ARRAY['draft','processing','authorized','rejected','error','cancelled','substituted'],\n 'declared')\nON CONFLICT (kind) DO UPDATE\n SET plugin = EXCLUDED.plugin,\n description = EXCLUDED.description,\n statuses = EXCLUDED.statuses,\n updated_at = now();\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. A extensão: o que só o fiscal entende\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_documents (\n -- A chave É o documento. Não há id próprio: a nota e o documento são a mesma\n -- coisa vista de dois lugares, e um segundo id só criaria a chance de eles\n -- discordarem.\n document_id uuid PRIMARY KEY REFERENCES public.documents(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n -- A comanda/pedido que originou a emissão.\n order_id uuid REFERENCES public.orders(id) ON DELETE SET NULL,\n model text NOT NULL,\n environment text,\n status text NOT NULL,\n series text,\n number text,\n -- 44 dígitos. Sem CHECK de formato: uma nota REJEITADA não tem chave, e uma\n -- chave que a SEFAZ devolveu torta é informação, não erro de digitação.\n access_key text,\n verification_code text,\n protocol text,\n provider text,\n provider_document_id text,\n provider_integration_id text,\n total_value numeric(14,2),\n iss_value numeric(14,2),\n recipient_snapshot jsonb,\n request_payload jsonb,\n response_payload jsonb,\n status_payload jsonb,\n rejection_payload jsonb,\n source_snapshot jsonb,\n -- O artefato legal. 5,6 kB por nota nas 113 que o têm; não se regenera.\n xml text,\n authorized_at timestamptz,\n last_polled_at timestamptz,\n emitted_by_user_id uuid,\n cancelled_at timestamptz,\n cancel_reason text,\n cancelled_by_user_id uuid,\n -- A cadeia de substituição. Auto-referência, então SET NULL: apagar a nota\n -- substituída não pode arrastar a que a substituiu.\n substitutes_document_id uuid REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE SET NULL,\n substituted_by_document_id uuid REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE SET NULL,\n observations text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nDO $$ BEGIN\n ALTER TABLE public.plg_fiscalbr_documents\n ADD CONSTRAINT plg_fiscalbr_documents_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\nEXCEPTION WHEN duplicate_object THEN NULL; END $$;\n\n-- A chave de acesso é única POR INQUILINO e só quando existe: 56 das 496 notas\n-- do Pertinho não têm chave nenhuma (rejeitadas e com erro), e um UNIQUE\n-- comum as empilharia todas num conflito só.\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_documents_chave_idx\n ON public.plg_fiscalbr_documents (tenant_id, access_key) WHERE access_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_documents_order_idx\n ON public.plg_fiscalbr_documents (tenant_id, order_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_documents_status_idx\n ON public.plg_fiscalbr_documents (tenant_id, unit_id, status, authorized_at DESC);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. A trilha da emissão\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1.886 eventos para 496 notas — quase quatro por nota. É aqui que a rejeição\n-- diz o motivo, e é o único lugar em que ela diz.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_document_events (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n document_id uuid NOT NULL REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE CASCADE,\n event_type text NOT NULL,\n status text,\n justification text,\n request_payload jsonb,\n response_payload jsonb,\n created_by_user_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_document_events_doc_idx\n ON public.plg_fiscalbr_document_events (document_id, created_at DESC);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. Quais vendas a nota cobre\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_document_orders (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n document_id uuid NOT NULL REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE CASCADE,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE CASCADE,\n created_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (document_id, order_id)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_document_orders_order_idx\n ON public.plg_fiscalbr_document_orders (tenant_id, order_id);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. updated_at e a cerca\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$ BEGIN\n CREATE TRIGGER plg_fiscalbr_documents_updated_at BEFORE UPDATE\n ON public.plg_fiscalbr_documents FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\nEXCEPTION WHEN duplicate_object THEN NULL; END $$;\n\n-- \\`app.current_tenant_id()\\` e não \\`user_tenant_ids()\\`, pela razão que a 013 do\n-- plugin-tables teve de consertar em produção: a segunda devolve a UNIÃO das\n-- contas do chamador e mostraria a nota fiscal de um cliente para outro.\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_documents','plg_fiscalbr_document_events',\n 'plg_fiscalbr_document_orders'] LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_select', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_insert', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_update', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_delete', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR SELECT USING (tenant_id = (select app.current_tenant_id()))', t || '_select', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR INSERT WITH CHECK (tenant_id = (select app.current_tenant_id()))', t || '_insert', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR UPDATE USING (tenant_id = (select app.current_tenant_id()))', t || '_update', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR DELETE USING (tenant_id = (select app.current_tenant_id()))', t || '_delete', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_006_O_GRUPO_FISCAL_GANHA_O_RAIL = `-- O grupo fiscal ganha observação e etiqueta.\n--\n-- A tabela existe desde a 002 e nunca teve TELA: o grupo fiscal de toda conta\n-- migrada estava no banco sem porta. Estas duas colunas são o que falta para\n-- ele ter o mesmo rail de todo cadastro do produto — e a etiqueta tem uso\n-- imediato aqui, porque «Simples», «monofásico» e «substituição tributária»\n-- são recortes que nenhum campo do grupo responde e que decidem qual grupo\n-- alguém procura.\n--\n-- Idempotente.\n\nALTER TABLE public.plg_fiscalbr_tax_groups\n ADD COLUMN IF NOT EXISTS notes text,\n ADD COLUMN IF NOT EXISTS tags text[] DEFAULT '{}'::text[],\n ADD COLUMN IF NOT EXISTS unit_id uuid;\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_tags_gin\n ON public.plg_fiscalbr_tax_groups USING gin (tags);\n`\n\nexport const MIGRATION_007_A_RLS_DO_DOCUMENTO_PASSA_A_SER_LEGIVEL = `-- ---------------------------------------------------------------------------\n-- 007_a_rls_do_documento_passa_a_ser_legivel.sql\n--\n-- MESMO caso da 036 do plugin-tables, e a mesma medição antes de escrever.\n--\n-- \\`check-plugin-review\\` reprovou estas tabelas com *«cria public.X com\n-- tenant_id e nunca liga row security»*. Fui ao banco: **todas têm RLS ligada,\n-- com políticas** — medido no cluster do Pertinho em 29-09:\n--\n-- plg_fiscalbr_documents ........ rls=t, 4 políticas\n-- plg_fiscalbr_document_events .. rls=t, 4\n-- plg_fiscalbr_document_orders .. rls=t, 4\n--\n-- Não há vazamento. O \\`ENABLE\\` dessas tabelas mora dentro de um\n-- \\`DO $$ … EXECUTE format(...)\\`, e o portão lê o ARQUIVO, não o banco — uma\n-- garantia que o revisor não consegue ler é uma garantia que ninguém confere.\n--\n-- As migrations que as criam JÁ FORAM APLICADAS; reescrevê-las trocaria o\n-- checksum, que é a deriva de ledger pela qual este repositório para o mundo.\n-- Então a legibilidade entra por arquivo NOVO — o portão pergunta ao SQL\n-- INTEIRO do plugin.\n--\n-- Ligar RLS já ligada é no-op: isto não muda comportamento, torna conferível o\n-- que já era verdade.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nALTER TABLE public.plg_fiscalbr_documents ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_document_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_document_orders ENABLE ROW LEVEL SECURITY;\n`\n\nexport const MIGRATION_008_A_NOTA_RECEBIDA_GUARDA_A_DECISAO_DE_ENTRADA = `-- ---------------------------------------------------------------------------\n-- 008_a_nota_recebida_guarda_a_decisao_de_entrada.sql\n--\n-- A 002 trouxe a nota; esta guarda o que se DECIDE sobre ela.\n--\n-- O inbox do V2 já sabe tudo que o XML diz: fornecedor, item, NCM, CFOP, os 30\n-- campos de tributo. O que não tem onde morar é a decisão que o operador toma\n-- em cima da nota, e é ela que transforma documento em estoque e em dinheiro:\n--\n-- a qual PRODUTO esta linha corresponde (product_id, já existia)\n-- que TIPO de entrada ela é (entry_type)\n-- em que UNIDADE de estoque, com que FATOR (stock_unit_id, conversion_factor)\n-- em que PLANO DE CONTAS ela cai (chart_account_id)\n-- com que CUSTO o produto fica (cost_mode, unit_cost_new)\n--\n-- Sem essas colunas a tela de conciliação não tem onde salvar, e \"importar nota\n-- fiscal\" viraria um leitor de XML — que é exatamente o que o V2 tinha.\n--\n-- ── O vocabulário vem do V1 medido, não de um enum inventado ────────────────\n--\n-- \\`danfe_import_items.entry_type\\` no V1 de produção (29-09-2026), 3.402 linhas:\n--\n-- insumo 2.303 revenda 546 patrimonio 280\n-- despesa 262 servico 11 (null) 5\n--\n-- São cinco, e duas delas — \\`despesa\\` e \\`servico\\` — NÃO viram estoque. É por\n-- isso que o tipo é coluna da linha e não da nota: a mesma NF-e traz o insumo\n-- que entra no estoque e a taxa de entrega que só vira despesa.\n--\n-- \\`cost_mode\\` tem UM valor em 3.407 linhas: \\`novo\\`. A média ponderada existe na\n-- tela do V1 e ninguém nunca escolheu. Fica no CHECK por paridade — tirar a\n-- opção é decisão de produto, e o dado não autoriza ninguém a tomá-la por aqui.\n--\n-- ── Por que \\`stock_movement_id\\` na linha, e não só na nota ──────────────────\n--\n-- Uma nota pode virar estoque PARCIALMENTE: o V1 tem os status \\`partial\\` e\n-- \\`partial_stocked\\` justamente porque o operador concilia 1 de 6 itens hoje e o\n-- resto amanhã. Guardar o movimento só no cabeçalho responderia \"esta nota\n-- entrou?\" e nunca \"esta LINHA entrou?\" — e é a segunda pergunta que decide se\n-- aceitar de novo duplica saldo.\n--\n-- ── O de-para é o que faz a segunda nota ser rápida ─────────────────────────\n--\n-- \\`supplier_product_mappings\\` no V1: (CNPJ do fornecedor, código do produto no\n-- fornecedor) → produto, tipo, plano, unidade, fator. 66 linhas na Artorius, e é\n-- o que faz a nota seguinte do mesmo fornecedor chegar já vinculada. Sem ele,\n-- toda importação recomeça do zero e o ganho de importar XML desaparece.\n--\n-- A chave é (tenant, CNPJ, código) e NÃO inclui unidade: o de-para é\n-- conhecimento sobre o catálogo do fornecedor, não sobre uma loja.\n--\n-- Aditivo e idempotente. Nada aqui apaga, renomeia ou reescreve dado existente.\n-- ---------------------------------------------------------------------------\n\n-- ── A decisão, linha a linha ────────────────────────────────────────────────\n\nALTER TABLE public.plg_fiscalbr_inbox_items\n ADD COLUMN IF NOT EXISTS entry_type text,\n ADD COLUMN IF NOT EXISTS chart_account_id uuid,\n ADD COLUMN IF NOT EXISTS stock_unit_id uuid,\n -- A quantidade que entra no estoque, já convertida. Derivada\n -- (quantity_commercial × conversion_factor), mas GRAVADA: é o número que o\n -- operador viu na tela antes de aceitar, e recalcular depois com um fator que\n -- alguém editou daria outra resposta para a mesma entrada.\n ADD COLUMN IF NOT EXISTS stock_quantity numeric(18,4),\n ADD COLUMN IF NOT EXISTS conversion_factor numeric(14,4) NOT NULL DEFAULT 1,\n ADD COLUMN IF NOT EXISTS cost_mode text,\n ADD COLUMN IF NOT EXISTS unit_cost_new numeric(18,6),\n -- O movimento que ESTA linha produziu. Nulo = não entrou.\n ADD COLUMN IF NOT EXISTS stock_movement_id uuid,\n -- Divergência: chegou menos do que a nota diz. O V1 guarda quantidade, motivo\n -- e observação, e a nota continua válida — quem responde pela diferença é o\n -- fornecedor, não o estoque.\n ADD COLUMN IF NOT EXISTS shortage_quantity numeric(18,4),\n ADD COLUMN IF NOT EXISTS shortage_reason text,\n ADD COLUMN IF NOT EXISTS shortage_note text;\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_entry_type_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_entry_type_chk\n CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','despesa','servico'));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_cost_mode_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_cost_mode_chk\n CHECK (cost_mode IS NULL OR cost_mode IN ('novo','media'));\n END IF;\n -- Um fator zero ou negativo não converte nada: transformaria a quantidade da\n -- nota em zero estoque sem ninguém acusar. É o defeito silencioso que o\n -- FLOW.md do V1 nomeia («fator de conversão errado é silencioso»), e aqui ele\n -- deixa de ser possível.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_factor_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_factor_chk CHECK (conversion_factor > 0);\n END IF;\nEND $$;\n\n-- FK lógica para o plano de contas e a unidade: as duas são de OUTROS plugins\n-- (financial e inventory), e a 000 deste plugin já estabelece que FK física\n-- entre plugins é proibida — instalar ou remover um addon não reescreve o\n-- schema do vizinho. A integridade é verificada na RPC, que é quem escreve.\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.chart_account_id IS\n 'Logical reference to plg_financial_chart_of_accounts.id — validated by the accept RPC, not by a cross-plugin FK.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.stock_unit_id IS\n 'Logical reference to plg_inventory_measurement_units.id — validated by the accept RPC.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.stock_quantity IS\n 'quantity_commercial x conversion_factor, stored as shown on screen before accepting.';\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_pending_idx\n ON public.plg_fiscalbr_inbox_items (tenant_id, inbox_document_id)\n WHERE reconciled IS NOT TRUE;\n\n-- ── A decisão no cabeçalho da nota ──────────────────────────────────────────\n\nALTER TABLE public.plg_fiscalbr_inbox_documents\n -- «itens sem plano herdarão este» — o plano da nota é padrão com HERANÇA, não\n -- obrigação por item. A frase é do V1 e a coluna existe para ela.\n ADD COLUMN IF NOT EXISTS default_chart_account_id uuid,\n -- O título a pagar que esta nota gerou. Mesma ideia do inventory_operation_id\n -- que a 002 já trouxe para o estoque: a nota aponta para as duas travessias.\n ADD COLUMN IF NOT EXISTS invoice_id uuid,\n ADD COLUMN IF NOT EXISTS stocked_at timestamptz,\n -- A natureza da operação declarada na NF-e («REM BONIFICACAO NAO\n -- CONTRIBUINTE»). O bloco de situação fiscal da conciliação mostra isso, e\n -- sem a coluna a tela mostraria um campo vazio.\n ADD COLUMN IF NOT EXISTS nature_operation text,\n ADD COLUMN IF NOT EXISTS default_location_id uuid;\n\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_documents.invoice_id IS\n 'Logical reference to plg_financial_invoices.id created by fiscalbr_accept_inbox_document.';\n\n-- ── A parcela sabe como se paga ─────────────────────────────────────────────\n--\n-- A duplicata do XML traz número, vencimento e valor. O que o operador acrescenta\n-- na tela é COMO ela se paga — e o boleto que ele anexa carrega o código de\n-- barras, que é o que a automação do V1 lê para preencher a parcela.\n\nALTER TABLE public.plg_fiscalbr_inbox_duplicates\n ADD COLUMN IF NOT EXISTS payment_type text,\n ADD COLUMN IF NOT EXISTS barcode text,\n ADD COLUMN IF NOT EXISTS pix_key text,\n ADD COLUMN IF NOT EXISTS payment_method_id uuid;\n\n-- O vocabulário é o do V1, medido em \\`danfe_payments.payment_type\\` (1.069 linhas):\n-- boleto 660 · sem_pagamento 108 · outro 107 · dinheiro 65 ·\n-- duplicata_mercantil 45 · pix 35 · cartao_credito 35 · cartao_debito 9 ·\n-- credito_loja 4 · vale_presente 1\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_payment_type_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_duplicates\n ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_payment_type_chk\n CHECK (payment_type IS NULL OR payment_type IN (\n 'boleto','pix','dinheiro','cartao_credito','cartao_debito',\n 'duplicata_mercantil','credito_loja','vale_presente','sem_pagamento','outro'));\n END IF;\nEND $$;\n\n-- ── O de-para fornecedor × produto ──────────────────────────────────────────\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_supplier_product_map (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Só dígitos, normalizado na escrita: o XML traz o CNPJ cru e a tela do V1\n -- aceitava pontuação, então duas grafias do mesmo fornecedor viravam dois\n -- de-para e a segunda nota não achava o primeiro.\n supplier_cnpj text NOT NULL,\n supplier_product_code text NOT NULL,\n product_id uuid NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,\n entry_type text,\n chart_account_id uuid,\n stock_unit_id uuid,\n conversion_factor numeric(14,4) NOT NULL DEFAULT 1,\n cost_mode text,\n -- Quantas vezes este de-para acertou. Serve para a tela mostrar de onde veio o\n -- vínculo («já usado 12 vezes») em vez de um produto que apareceu sozinho.\n hit_count integer NOT NULL DEFAULT 0,\n last_used_at timestamptz,\n owner_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_fiscalbr_supplier_product_map_factor_chk CHECK (conversion_factor > 0),\n CONSTRAINT plg_fiscalbr_supplier_product_map_entry_type_chk\n CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','despesa','servico')),\n CONSTRAINT plg_fiscalbr_supplier_product_map_cost_mode_chk\n CHECK (cost_mode IS NULL OR cost_mode IN ('novo','media'))\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_supplier_product_map_uq\n ON public.plg_fiscalbr_supplier_product_map (tenant_id, supplier_cnpj, supplier_product_code);\n\nALTER TABLE public.plg_fiscalbr_supplier_product_map ENABLE ROW LEVEL SECURITY;\n\n-- Mesmas políticas das tabelas do inbox (002): o de-para é conhecimento do\n-- financeiro sobre o fornecedor, então lê com \\`financial.read\\` e escreve com\n-- \\`financial.edit\\`. Não tem unit_id — é catálogo do fornecedor, não da loja.\nDROP POLICY IF EXISTS plg_fiscalbr_supplier_product_map_authz_select ON public.plg_fiscalbr_supplier_product_map;\nCREATE POLICY plg_fiscalbr_supplier_product_map_authz_select\n ON public.plg_fiscalbr_supplier_product_map FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL::uuid)));\n\nDROP POLICY IF EXISTS plg_fiscalbr_supplier_product_map_authz_write ON public.plg_fiscalbr_supplier_product_map;\nCREATE POLICY plg_fiscalbr_supplier_product_map_authz_write\n ON public.plg_fiscalbr_supplier_product_map FOR ALL TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', NULL::uuid)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', NULL::uuid)));\n\nCOMMENT ON TABLE public.plg_fiscalbr_supplier_product_map IS\n 'Supplier catalogue memory: (CNPJ, supplier product code) -> the entry decision, so the next note from the same supplier arrives already bound. Mirrors V1 supplier_product_mappings.';\n`\n\nexport const MIGRATION_009_ACEITAR_A_NOTA_ESCREVE_ESTOQUE_E_TITULO_DE_UMA_VEZ = `-- ---------------------------------------------------------------------------\n-- 009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez.sql\n--\n-- É o arquivo que fecha o porte: «Aceitar» na conciliação dá entrada no estoque\n-- E cria a conta a pagar, numa transação só.\n--\n-- Medido no V1 de produção (tenant 12 da Artorius, 29-09-2026): **72 de 72**\n-- movimentos de estoque nasceram com \\`danfe_import_item_id\\`. Nenhum foi digitado.\n-- Dar ao V2 uma tela de movimentação manual e chamar isso de paridade seria\n-- entregar a tela que eles nunca abriram.\n--\n-- ── Não reimplementa estoque nem título. CHAMA quem já faz ──────────────────\n--\n-- O V2 já tem as duas primitivas, e as duas já são idempotentes:\n--\n-- public.inventory_receive(location, lines, document, idempotency_key)\n-- public.financial_create_invoice(direction, total, counterparty, …, key)\n--\n-- Reescrever INSERT em \\`plg_inventory_stock_movements\\` aqui daria uma segunda\n-- resposta para «como entra estoque» — e a posição é derivada por gatilho, então\n-- a segunda resposta sairia com saldo certo e sem ninguém acusar. A entrada de\n-- nota é mais um CHAMADOR dessas portas, como a requisição e a contagem.\n--\n-- Idempotência vem de graça daí: a chave é derivada da chave de acesso da NF-e,\n-- que é única por documento fiscal no Brasil. Aceitar duas vezes devolve o mesmo\n-- resultado sem escrever de novo — o AC7 do plano.\n--\n-- ── O total do título é a soma das PARCELAS ────────────────────────────────\n--\n-- Regra herdada da \\`plugin-financial/084\\`, que mediu: em 6,3% das notas a soma\n-- das duplicatas não bate com o total da nota. \\`plg_financial_invoices\\` é\n-- imutável depois de emitido, então um título aberto com o total errado fica\n-- com saldo errado para sempre em toda tela que faz «total − pago».\n-- O total da nota continua legível no \\`metadata\\` e na caixa de entrada.\n--\n-- E a MESMA chave de idempotência da 084 (\\`danfe:<chave>\\`): uma nota que o porte\n-- histórico já transformou em título não pode ganhar um segundo aqui.\n--\n-- ── Despesa e serviço não viram estoque ────────────────────────────────────\n--\n-- \\`entry_type\\` decide por LINHA. A mesma NF-e traz o insumo que entra no estoque\n-- e a taxa de entrega que só vira despesa — e as duas precisam ir para o mesmo\n-- título a pagar. Por isso a lista de linhas do estoque é um FILTRO sobre os\n-- itens, não os itens.\n--\n-- Idempotente. Só cria função.\n-- ---------------------------------------------------------------------------\n\n-- ── Ajudantes ──────────────────────────────────────────────────────────────\n\n-- O XML traz o CNPJ cru e a tela aceita pontuação. Duas grafias do mesmo\n-- fornecedor viravam dois de-para no V1, e a segunda nota não achava o primeiro.\nCREATE OR REPLACE FUNCTION public.plg_fiscalbr_digits(p_value text)\nRETURNS text LANGUAGE sql IMMUTABLE SET search_path TO '' AS $$\n SELECT regexp_replace(coalesce(p_value, ''), '[^0-9]', '', 'g')\n$$;\n\n-- ── Receber a nota: o XML já lido vira linhas ──────────────────────────────\n--\n-- O XML é decomposto no NAVEGADOR e chega aqui como jsonb. Parsear NF-e em\n-- PL/pgSQL seria escrever um leitor de XML dentro do banco, sem teste unitário\n-- possível e sem a mensagem de erro que a tela precisa dar para um arquivo que\n-- não é uma nota.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_stage_inbox_document(p_note jsonb)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_key text := btrim(coalesce(p_note->>'access_key', ''));\n v_cnpj text := public.plg_fiscalbr_digits(p_note->'supplier'->>'cnpj');\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_unit uuid := nullif(p_note->>'unit_id', '')::uuid;\n v_party uuid;\n v_item jsonb;\n v_map public.plg_fiscalbr_supplier_product_map%ROWTYPE;\n v_n integer := 0;\n v_matched integer := 0;\nBEGIN\n PERFORM public.plg_financial_require_permission('financial.create', v_unit);\n\n IF length(v_key) <> 44 THEN\n RAISE EXCEPTION 'fiscalbr: chave de acesso inválida (esperado 44 dígitos, veio %)', length(v_key)\n USING ERRCODE = '22023';\n END IF;\n\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND access_key = v_key;\n\n -- Nota já aceita não é reimportada: o XML é o mesmo documento fiscal, e\n -- reescrever os itens apagaria a decisão que virou estoque e título.\n IF FOUND AND (v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL) THEN\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'access_key', v_key, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'items', 0, 'matched', 0);\n END IF;\n\n -- O fornecedor é uma PESSOA, não um nome. A 094 do financial documenta o custo\n -- de não ter o ponteiro: praticamente todo título nascido de DANFE ficou sem\n -- contraparte. Casar por CNPJ acerta; casar por nome acertaria 137 de 554.\n IF v_cnpj <> '' THEN\n SELECT id INTO v_party FROM public.people\n WHERE tenant_id = v_tenant AND public.plg_fiscalbr_digits(document_number) = v_cnpj\n LIMIT 1;\n END IF;\n\n INSERT INTO public.plg_fiscalbr_inbox_documents (\n tenant_id, unit_id, access_key, nfe_number, nfe_series, nfe_model, issue_date,\n received_at, status, nature_operation, supplier_party_id, supplier_cnpj,\n supplier_name, supplier_ie, total_value, total_products, total_discount,\n total_freight, total_insurance, total_other, additional_info, metadata)\n VALUES (\n v_tenant, v_unit, v_key, p_note->>'nfe_number', p_note->>'nfe_series',\n coalesce(p_note->>'nfe_model', '55'), nullif(p_note->>'issue_date', '')::date,\n now(), 'pending', p_note->>'nature_operation', v_party, nullif(v_cnpj, ''),\n p_note->'supplier'->>'name', p_note->'supplier'->>'ie',\n (p_note->'totals'->>'total')::numeric, (p_note->'totals'->>'products')::numeric,\n (p_note->'totals'->>'discount')::numeric, (p_note->'totals'->>'freight')::numeric,\n (p_note->'totals'->>'insurance')::numeric, (p_note->'totals'->>'other')::numeric,\n p_note->>'additional_info',\n jsonb_build_object('source', coalesce(p_note->>'source', 'xml_upload')))\n -- O índice único da 002 é PARCIAL (\\`WHERE access_key IS NOT NULL\\`), e a\n -- inferência do ON CONFLICT só o alcança repetindo o predicado. Sem ele o\n -- INSERT levanta «no unique or exclusion constraint matching» — e levantaria\n -- na primeira reimportação, não na aplicação.\n ON CONFLICT (tenant_id, access_key) WHERE access_key IS NOT NULL DO UPDATE SET\n -- Reimportar o mesmo XML corrige o cabeçalho; a contraparte só é preenchida\n -- quando está vazia, para não desfazer uma costura feita à mão.\n nfe_number = EXCLUDED.nfe_number,\n nature_operation = coalesce(EXCLUDED.nature_operation, public.plg_fiscalbr_inbox_documents.nature_operation),\n supplier_party_id = coalesce(public.plg_fiscalbr_inbox_documents.supplier_party_id, EXCLUDED.supplier_party_id),\n supplier_name = EXCLUDED.supplier_name,\n total_value = EXCLUDED.total_value,\n updated_at = now()\n RETURNING * INTO v_doc;\n\n -- Os itens e as duplicatas são do DOCUMENTO, não do operador: vêm do XML e\n -- podem ser reescritos enquanto a nota não foi aceita.\n DELETE FROM public.plg_fiscalbr_inbox_items WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n DELETE FROM public.plg_fiscalbr_inbox_duplicates WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n DELETE FROM public.plg_fiscalbr_inbox_payments WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n FOR v_item IN SELECT * FROM jsonb_array_elements(coalesce(p_note->'items', '[]'::jsonb)) LOOP\n v_n := v_n + 1;\n\n -- O de-para: a segunda nota do mesmo fornecedor chega já vinculada. É o que\n -- faz importar XML valer a pena — sem ele toda nota recomeça do zero.\n SELECT * INTO v_map FROM public.plg_fiscalbr_supplier_product_map\n WHERE tenant_id = v_tenant AND supplier_cnpj = v_cnpj\n AND supplier_product_code = coalesce(v_item->>'supplier_product_code', '');\n IF FOUND THEN v_matched := v_matched + 1; END IF;\n\n INSERT INTO public.plg_fiscalbr_inbox_items (\n tenant_id, inbox_document_id, item_number, supplier_product_code, ean_barcode,\n description, ncm, cest, cfop, unit_commercial, quantity_commercial,\n unit_price_commercial, total_price, discount, freight, other_expenses,\n icms_cst, icms_csosn, icms_base, icms_rate, icms_value,\n pis_value, cofins_value, ipi_value, raw_xml_item,\n product_id, entry_type, chart_account_id, stock_unit_id, conversion_factor,\n cost_mode, reconciled, stock_quantity, unit_cost_new)\n VALUES (\n v_tenant, v_doc.id, coalesce((v_item->>'item_number')::int, v_n),\n v_item->>'supplier_product_code', v_item->>'ean_barcode',\n v_item->>'description', v_item->>'ncm', v_item->>'cest', v_item->>'cfop',\n v_item->>'unit', (v_item->>'quantity')::numeric,\n (v_item->>'unit_price')::numeric, (v_item->>'total')::numeric,\n (v_item->>'discount')::numeric, (v_item->>'freight')::numeric,\n (v_item->>'other')::numeric,\n v_item->>'icms_cst', v_item->>'icms_csosn', (v_item->>'icms_base')::numeric,\n (v_item->>'icms_rate')::numeric, (v_item->>'icms_value')::numeric,\n (v_item->>'pis_value')::numeric, (v_item->>'cofins_value')::numeric,\n (v_item->>'ipi_value')::numeric, v_item,\n v_map.product_id, v_map.entry_type, v_map.chart_account_id, v_map.stock_unit_id,\n coalesce(v_map.conversion_factor, 1), coalesce(v_map.cost_mode, 'novo'),\n v_map.product_id IS NOT NULL,\n -- A quantidade de estoque já sai calculada quando o de-para deu o fator: é\n -- o número que a tela mostra antes de aceitar.\n CASE WHEN v_map.product_id IS NOT NULL\n THEN (v_item->>'quantity')::numeric * coalesce(v_map.conversion_factor, 1) END,\n CASE WHEN v_map.product_id IS NOT NULL AND coalesce(v_map.conversion_factor, 1) > 0\n THEN (v_item->>'unit_price')::numeric / coalesce(v_map.conversion_factor, 1) END);\n END LOOP;\n\n INSERT INTO public.plg_fiscalbr_inbox_duplicates (\n tenant_id, inbox_document_id, duplicate_index, number, due_date, value, payment_type)\n SELECT v_tenant, v_doc.id, coalesce((d->>'index')::int, ord), d->>'number',\n nullif(d->>'due_date', '')::date, (d->>'value')::numeric,\n nullif(d->>'payment_type', '')\n FROM jsonb_array_elements(coalesce(p_note->'duplicates', '[]'::jsonb)) WITH ORDINALITY AS t(d, ord);\n\n INSERT INTO public.plg_fiscalbr_inbox_payments (\n tenant_id, inbox_document_id, payment_index, payment_indicator,\n payment_type_code, payment_type_label, value)\n SELECT v_tenant, v_doc.id, coalesce((p->>'index')::int, ord), p->>'indicator',\n p->>'code', p->>'label', (p->>'value')::numeric\n FROM jsonb_array_elements(coalesce(p_note->'payments', '[]'::jsonb)) WITH ORDINALITY AS t(p, ord);\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'access_key', v_key, 'already_accepted', false,\n 'supplier_party_id', v_party, 'items', v_n, 'matched', v_matched);\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_stage_inbox_document(jsonb) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_stage_inbox_document(jsonb) TO authenticated;\n\n-- ── Salvar a conciliação sem aceitar ───────────────────────────────────────\n--\n-- Conciliar e estocar são duas coisas no V1 — daí as duas colunas na lista, e\n-- daí a fila de 55 notas conciliadas e não estocadas. Quem salva o vínculo não\n-- está mandando dar entrada.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_save_inbox_decision(\n p_document_id uuid,\n p_items jsonb,\n p_default_chart_account_id uuid DEFAULT NULL,\n p_default_location_id uuid DEFAULT NULL,\n p_duplicates jsonb DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_row jsonb;\n v_done integer := 0;\n v_total integer;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.edit', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RAISE EXCEPTION 'fiscalbr: nota % já foi aceita — a decisão não muda depois do estoque', p_document_id\n USING ERRCODE = '23514';\n END IF;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n default_chart_account_id = coalesce(p_default_chart_account_id, default_chart_account_id),\n default_location_id = coalesce(p_default_location_id, default_location_id),\n reviewed_at = now(), updated_at = now()\n WHERE id = v_doc.id;\n\n FOR v_row IN SELECT * FROM jsonb_array_elements(coalesce(p_items, '[]'::jsonb)) LOOP\n UPDATE public.plg_fiscalbr_inbox_items i SET\n product_id = nullif(v_row->>'product_id', '')::uuid,\n entry_type = nullif(v_row->>'entry_type', ''),\n chart_account_id = nullif(v_row->>'chart_account_id', '')::uuid,\n stock_unit_id = nullif(v_row->>'stock_unit_id', '')::uuid,\n conversion_factor = coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1),\n cost_mode = coalesce(nullif(v_row->>'cost_mode', ''), 'novo'),\n shortage_quantity = nullif(v_row->>'shortage_quantity', '')::numeric,\n shortage_reason = nullif(v_row->>'shortage_reason', ''),\n shortage_note = nullif(v_row->>'shortage_note', ''),\n -- Derivadas, gravadas: é o que o operador viu.\n stock_quantity = i.quantity_commercial * coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1)\n - coalesce(nullif(v_row->>'shortage_quantity', '')::numeric, 0),\n unit_cost_new = CASE WHEN coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1) > 0\n THEN i.unit_price_commercial / coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1) END,\n -- Uma linha está conciliada quando sabe o que é. Despesa e serviço não\n -- pedem produto: elas nunca vão virar estoque.\n reconciled = CASE\n WHEN nullif(v_row->>'entry_type', '') IN ('despesa','servico') THEN true\n ELSE nullif(v_row->>'product_id', '') IS NOT NULL\n END,\n updated_at = now()\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.id = (v_row->>'id')::uuid;\n v_done := v_done + 1;\n END LOOP;\n\n IF p_duplicates IS NOT NULL THEN\n DELETE FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n INSERT INTO public.plg_fiscalbr_inbox_duplicates (\n tenant_id, inbox_document_id, duplicate_index, number, due_date, value,\n payment_type, barcode, pix_key, payment_method_id)\n SELECT v_tenant, v_doc.id, coalesce((d->>'index')::int, ord), d->>'number',\n nullif(d->>'due_date', '')::date, (d->>'value')::numeric,\n nullif(d->>'payment_type', ''), nullif(d->>'barcode', ''),\n nullif(d->>'pix_key', ''), nullif(d->>'payment_method_id', '')::uuid\n FROM jsonb_array_elements(p_duplicates) WITH ORDINALITY AS t(d, ord);\n END IF;\n\n SELECT count(*) INTO v_total FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET status = CASE\n WHEN (SELECT count(*) FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id AND reconciled) = v_total\n THEN 'accepted' ELSE 'partial' END\n WHERE id = v_doc.id;\n\n RETURN jsonb_build_object('document_id', v_doc.id, 'saved', v_done, 'items', v_total,\n 'reconciled', (SELECT count(*) FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id AND reconciled));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_save_inbox_decision(uuid, jsonb, uuid, uuid, jsonb) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_save_inbox_decision(uuid, jsonb, uuid, uuid, jsonb) TO authenticated;\n\n-- ── Aceitar: estoque e título, de uma vez ──────────────────────────────────\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_accept_inbox_document(\n p_document_id uuid,\n p_location_id uuid DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_loc uuid;\n v_lines jsonb := '[]'::jsonb;\n v_insts jsonb := '[]'::jsonb;\n v_recv jsonb;\n v_inv jsonb;\n v_it record;\n v_no integer := 0;\n v_total numeric := 0;\n v_stock_n integer := 0;\n v_key text;\n v_invoice uuid;\n -- Posição na lista de linhas → id do item da nota. \\`line_no\\` do movimento\n -- indexa este array direto.\n v_item_ids uuid[] := '{}';\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.create', v_doc.unit_id);\n\n -- Já aceita devolve o que aceitou. Não é erro: é a segunda vez que o operador\n -- clicou, e o AC7 diz que isso não pode dobrar nada.\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RETURN jsonb_build_object('document_id', v_doc.id, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'operation_id', v_doc.inventory_operation_id);\n END IF;\n\n v_loc := coalesce(p_location_id, v_doc.default_location_id);\n\n -- Toda linha tem de saber o que é. Aceitar uma nota com item sem tipo gravaria\n -- um título cujo rateio ninguém consegue explicar depois.\n IF EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND (entry_type IS NULL OR entry_type = '')) THEN\n RAISE EXCEPTION 'fiscalbr: há item sem tipo de registro — conciliar antes de aceitar'\n USING ERRCODE = '23514';\n END IF;\n\n -- As linhas que viram estoque. Despesa e serviço ficam fora daqui e entram só\n -- no título.\n FOR v_it IN\n SELECT * FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND entry_type IN ('insumo','revenda','patrimonio')\n ORDER BY item_number\n LOOP\n IF v_it.product_id IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: item % é % e não tem produto vinculado', v_it.item_number, v_it.entry_type\n USING ERRCODE = '23514';\n END IF;\n v_no := v_no + 1;\n -- A ordem desta lista É o \\`line_no\\` que o movimento vai carregar. Guardo o\n -- id da linha na mesma posição para devolver o movimento ao item sem\n -- reconsultar — e sem depender de casar por produto, que repete quando a\n -- mesma mercadoria vem em duas linhas da nota.\n v_item_ids := v_item_ids || v_it.id;\n v_lines := v_lines || jsonb_build_object(\n 'product_id', v_it.product_id,\n 'quantity', coalesce(v_it.stock_quantity, v_it.quantity_commercial * v_it.conversion_factor),\n 'unit_cost', coalesce(v_it.unit_cost_new, v_it.unit_price_commercial / v_it.conversion_factor),\n 'measurement_unit_id', v_it.stock_unit_id,\n 'notes', v_it.description);\n END LOOP;\n v_stock_n := v_no;\n\n IF v_stock_n > 0 THEN\n IF v_loc IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: a nota tem % linha(s) de estoque e nenhum local de estoque escolhido', v_stock_n\n USING ERRCODE = '22023';\n END IF;\n -- A chave de acesso é única por documento fiscal no Brasil: é a chave de\n -- idempotência natural, e é ela que faz o segundo clique não dobrar saldo.\n v_recv := public.inventory_receive(\n v_loc, v_lines,\n jsonb_build_object(\n 'supplier_id', v_doc.supplier_party_id,\n 'date', v_doc.issue_date,\n 'type', 'nfe',\n 'ref', 'NF-e ' || coalesce(v_doc.nfe_number, '?'),\n 'notes', 'Entrada via DANFE NF-e ' || coalesce(v_doc.nfe_number, '?')),\n 'nfe:' || v_doc.access_key);\n\n -- Cada movimento volta para a SUA linha. Guardar só no cabeçalho responderia\n -- «esta nota entrou?» e nunca «esta linha entrou?» — e é a segunda pergunta\n -- que a conciliação parcial faz.\n --\n -- \\`line_no\\` do movimento é a posição na lista que montei acima, e\n -- \\`v_item_ids\\` está na mesma ordem: um join, não uma varredura por posição.\n UPDATE public.plg_fiscalbr_inbox_items i\n SET stock_movement_id = m.movement_id, updated_at = now()\n FROM (\n SELECT v_item_ids[(mov->>'line_no')::int] AS item_id, (mov->>'id')::uuid AS movement_id\n FROM jsonb_array_elements(coalesce(v_recv->'movements', '[]'::jsonb)) AS t(mov)\n WHERE (mov->>'line_no') IS NOT NULL\n ) m\n WHERE i.tenant_id = v_tenant AND i.id = m.item_id;\n END IF;\n\n -- ── O título ─────────────────────────────────────────────────────────────\n -- Total = soma das PARCELAS (regra da financial/084). Nota sem duplicata vira\n -- uma parcela só, no vencimento que a nota declarar ou na emissão.\n SELECT coalesce(sum(value), 0),\n coalesce(jsonb_agg(jsonb_build_object(\n 'number', coalesce(duplicate_index, 1),\n 'due_date', coalesce(due_date, v_doc.issue_date, current_date),\n 'amount', round(value, 2),\n 'metadata', jsonb_strip_nulls(jsonb_build_object(\n 'barcode', barcode, 'pixKey', pix_key, 'paymentType', payment_type,\n 'danfeNumber', number))) ORDER BY duplicate_index), '[]'::jsonb)\n INTO v_total, v_insts\n FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n IF jsonb_array_length(v_insts) = 0 THEN\n v_total := round(coalesce(v_doc.total_value, 0), 2);\n v_insts := jsonb_build_array(jsonb_build_object(\n 'number', 1, 'due_date', coalesce(v_doc.issue_date, current_date), 'amount', v_total));\n ELSE\n v_total := round(v_total, 2);\n END IF;\n\n -- A MESMA chave da 084: nota já transformada em título pelo porte histórico\n -- não ganha um segundo aqui.\n v_key := 'danfe:' || v_doc.access_key;\n\n v_inv := public.financial_create_invoice(\n 'payable', v_total, v_doc.supplier_party_id, NULL, v_doc.unit_id, v_insts,\n v_doc.issue_date,\n 'NF-e ' || coalesce(v_doc.nfe_number, '?') || ' · ' || coalesce(v_doc.supplier_name, 'fornecedor'),\n NULL,\n jsonb_build_object(\n 'source', 'danfe',\n 'danfe', jsonb_strip_nulls(jsonb_build_object(\n 'accessKey', v_doc.access_key, 'number', v_doc.nfe_number,\n 'series', v_doc.nfe_series, 'supplierName', v_doc.supplier_name,\n 'supplierCnpj', v_doc.supplier_cnpj,\n -- O total da NOTA continua legível, mesmo quando difere do total do\n -- título. É a diferença que a 084 mediu em 6,3% das notas.\n 'noteTotal', v_doc.total_value,\n 'inboxDocumentId', v_doc.id))),\n v_key);\n v_invoice := (v_inv->>'invoice_id')::uuid;\n\n -- As linhas do título: TODOS os itens, inclusive despesa e serviço. É o que\n -- responde «de que essa conta é feita».\n INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)\n SELECT v_tenant, v_invoice, i.description, i.quantity_commercial, i.unit_price_commercial,\n round(coalesce(i.total_price, 0), 2), i.item_number,\n jsonb_strip_nulls(jsonb_build_object(\n 'itemKind', i.entry_type, 'referenceId', i.product_id,\n 'chartAccountId', i.chart_account_id, 'ncm', i.ncm, 'cfop', i.cfop,\n 'supplierProductCode', i.supplier_product_code))\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n ORDER BY i.item_number\n ON CONFLICT DO NOTHING;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n invoice_id = v_invoice,\n inventory_operation_id = coalesce((v_recv->>'operation_id')::uuid, inventory_operation_id),\n stocked_at = CASE WHEN v_stock_n > 0 THEN now() ELSE stocked_at END,\n status = 'accepted', updated_at = now()\n WHERE id = v_doc.id;\n\n -- ── O de-para aprende ────────────────────────────────────────────────────\n -- A decisão desta nota é o que faz a próxima do mesmo fornecedor chegar\n -- pronta. Guardar isto é o que separa «importei XML» de «o sistema sabe o meu\n -- fornecedor».\n INSERT INTO public.plg_fiscalbr_supplier_product_map (\n tenant_id, supplier_cnpj, supplier_product_code, product_id, entry_type,\n chart_account_id, stock_unit_id, conversion_factor, cost_mode, hit_count, last_used_at)\n SELECT v_tenant, v_doc.supplier_cnpj, i.supplier_product_code, i.product_id,\n i.entry_type, coalesce(i.chart_account_id, v_doc.default_chart_account_id),\n i.stock_unit_id, i.conversion_factor, i.cost_mode, 1, now()\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.product_id IS NOT NULL\n AND coalesce(v_doc.supplier_cnpj, '') <> ''\n AND coalesce(i.supplier_product_code, '') <> ''\n ON CONFLICT (tenant_id, supplier_cnpj, supplier_product_code) DO UPDATE SET\n product_id = EXCLUDED.product_id,\n entry_type = EXCLUDED.entry_type,\n chart_account_id = coalesce(EXCLUDED.chart_account_id, public.plg_fiscalbr_supplier_product_map.chart_account_id),\n stock_unit_id = coalesce(EXCLUDED.stock_unit_id, public.plg_fiscalbr_supplier_product_map.stock_unit_id),\n conversion_factor = EXCLUDED.conversion_factor,\n cost_mode = EXCLUDED.cost_mode,\n hit_count = public.plg_fiscalbr_supplier_product_map.hit_count + 1,\n last_used_at = now(),\n updated_at = now();\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'already_accepted', false,\n 'invoice_id', v_invoice, 'invoice_total', v_total,\n 'installments', jsonb_array_length(v_insts),\n 'operation_id', v_recv->>'operation_id',\n 'stock_lines', v_stock_n,\n 'movements', coalesce(v_recv->'movements', '[]'::jsonb));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) TO authenticated;\n\n-- ── Rejeitar ───────────────────────────────────────────────────────────────\n-- O rodapé do diálogo do V1 tem dois botões, e o outro também precisa existir:\n-- recusar a nota é dizer que ela não vira nada aqui — sem apagar o documento,\n-- que é fiscal e tem de continuar legível.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_reject_inbox_document(\n p_document_id uuid, p_reason text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.edit', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RAISE EXCEPTION 'fiscalbr: nota % já virou estoque ou título — recusar não desfaz', p_document_id\n USING ERRCODE = '23514';\n END IF;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n status = 'rejected',\n metadata = metadata || jsonb_strip_nulls(jsonb_build_object('rejectReason', p_reason)),\n reviewed_at = now(), updated_at = now()\n WHERE id = v_doc.id;\n\n RETURN jsonb_build_object('document_id', v_doc.id, 'status', 'rejected');\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_reject_inbox_document(uuid, text) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_reject_inbox_document(uuid, text) TO authenticated;\n`\n\nexport const MIGRATION_010_A_DATA_DE_EMISSAO_E_INSTANTE_E_A_COMPETENCIA_E_DIA = `-- ---------------------------------------------------------------------------\n-- 010_a_data_de_emissao_e_instante_e_a_competencia_e_dia.sql\n--\n-- A 009 não conseguia aceitar nota nenhuma. Descoberto no primeiro teste com\n-- usuário logado de verdade, que é onde ela ia ser usada:\n--\n-- POST rpc/fiscalbr_accept_inbox_document → 404\n-- function public.financial_create_invoice(unknown, numeric, uuid, unknown,\n-- uuid, jsonb, timestamp with time zone, text, unknown, jsonb, text)\n-- does not exist\n--\n-- \\`plg_fiscalbr_inbox_documents.issue_date\\` é **timestamptz** — a NF-e declara um\n-- INSTANTE (\\`dhEmi\\`, com fuso), e a 002 preservou isso. Eu escrevi a chamada\n-- supondo \\`date\\`, e \\`financial_create_invoice\\` pede \\`p_competence_date date\\`.\n--\n-- Nenhum teste pegou porque nenhum podia: o SQL aplica, a função compila (o corpo\n-- de PL/pgSQL não resolve assinatura em CREATE), e o erro só existe na chamada.\n-- Foi preciso um usuário logado percorrendo o caminho.\n--\n-- ── Duas correções, não uma ────────────────────────────────────────────────\n--\n-- 1. \\`issue_date::date\\` onde a competência é pedida. Instante é quando a nota foi\n-- emitida; competência é o DIA a que o título pertence, e o mês do título vem\n-- dela — um \\`timestamptz\\` viajando para lá levaria fuso para dentro de uma\n-- conta contábil.\n--\n-- 2. **Todo argumento tipado na chamada.** A chamada posicional passava \\`'payable'\\`\n-- e \\`NULL\\` sem tipo, e o Postgres tem de adivinhar entre as sobrecargas. Adivinhar\n-- certo hoje e errado quando alguém acrescentar uma sobrecarga é o defeito que\n-- volta meses depois sem ninguém mexer neste arquivo. Agora vai \\`::text\\`,\n-- \\`::uuid\\`, \\`::date\\` em tudo.\n--\n-- Idempotente: só substitui o corpo de uma função.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_accept_inbox_document(\n p_document_id uuid,\n p_location_id uuid DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_loc uuid;\n v_lines jsonb := '[]'::jsonb;\n v_insts jsonb := '[]'::jsonb;\n v_recv jsonb;\n v_inv jsonb;\n v_it record;\n v_no integer := 0;\n v_total numeric := 0;\n v_stock_n integer := 0;\n v_key text;\n v_invoice uuid;\n v_item_ids uuid[] := '{}';\n -- A competência: o DIA da emissão, não o instante.\n v_competence date;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.create', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RETURN jsonb_build_object('document_id', v_doc.id, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'operation_id', v_doc.inventory_operation_id);\n END IF;\n\n v_loc := coalesce(p_location_id, v_doc.default_location_id);\n v_competence := (v_doc.issue_date)::date;\n\n IF EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND (entry_type IS NULL OR entry_type = '')) THEN\n RAISE EXCEPTION 'fiscalbr: há item sem tipo de registro — conciliar antes de aceitar'\n USING ERRCODE = '23514';\n END IF;\n\n FOR v_it IN\n SELECT * FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND entry_type IN ('insumo','revenda','patrimonio')\n ORDER BY item_number\n LOOP\n IF v_it.product_id IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: item % é % e não tem produto vinculado', v_it.item_number, v_it.entry_type\n USING ERRCODE = '23514';\n END IF;\n v_no := v_no + 1;\n v_item_ids := v_item_ids || v_it.id;\n v_lines := v_lines || jsonb_build_object(\n 'product_id', v_it.product_id,\n 'quantity', coalesce(v_it.stock_quantity, v_it.quantity_commercial * v_it.conversion_factor),\n 'unit_cost', coalesce(v_it.unit_cost_new, v_it.unit_price_commercial / v_it.conversion_factor),\n 'measurement_unit_id', v_it.stock_unit_id,\n 'notes', v_it.description);\n END LOOP;\n v_stock_n := v_no;\n\n IF v_stock_n > 0 THEN\n IF v_loc IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: a nota tem % linha(s) de estoque e nenhum local de estoque escolhido', v_stock_n\n USING ERRCODE = '22023';\n END IF;\n v_recv := public.inventory_receive(\n v_loc::uuid,\n v_lines::jsonb,\n jsonb_build_object(\n 'supplier_id', v_doc.supplier_party_id,\n -- O documento do estoque também quer o DIA.\n 'date', v_competence,\n 'type', 'nfe',\n 'ref', 'NF-e ' || coalesce(v_doc.nfe_number, '?'),\n 'notes', 'Entrada via DANFE NF-e ' || coalesce(v_doc.nfe_number, '?')),\n ('nfe:' || v_doc.access_key)::text);\n\n UPDATE public.plg_fiscalbr_inbox_items i\n SET stock_movement_id = m.movement_id, updated_at = now()\n FROM (\n SELECT v_item_ids[(mov->>'line_no')::int] AS item_id, (mov->>'id')::uuid AS movement_id\n FROM jsonb_array_elements(coalesce(v_recv->'movements', '[]'::jsonb)) AS t(mov)\n WHERE (mov->>'line_no') IS NOT NULL\n ) m\n WHERE i.tenant_id = v_tenant AND i.id = m.item_id;\n END IF;\n\n SELECT coalesce(sum(value), 0),\n coalesce(jsonb_agg(jsonb_build_object(\n 'number', coalesce(duplicate_index, 1),\n 'due_date', coalesce(due_date, v_competence, current_date),\n 'amount', round(value, 2),\n 'metadata', jsonb_strip_nulls(jsonb_build_object(\n 'barcode', barcode, 'pixKey', pix_key, 'paymentType', payment_type,\n 'danfeNumber', number))) ORDER BY duplicate_index), '[]'::jsonb)\n INTO v_total, v_insts\n FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n IF jsonb_array_length(v_insts) = 0 THEN\n v_total := round(coalesce(v_doc.total_value, 0), 2);\n v_insts := jsonb_build_array(jsonb_build_object(\n 'number', 1, 'due_date', coalesce(v_competence, current_date), 'amount', v_total));\n ELSE\n v_total := round(v_total, 2);\n END IF;\n\n v_key := 'danfe:' || v_doc.access_key;\n\n -- TODO argumento tipado. A chamada posicional sem tipo obrigava o Postgres a\n -- adivinhar entre sobrecargas, e foi assim que esta função nasceu quebrada.\n v_inv := public.financial_create_invoice(\n 'payable'::text,\n v_total::numeric,\n v_doc.supplier_party_id::uuid,\n NULL::uuid,\n v_doc.unit_id::uuid,\n v_insts::jsonb,\n v_competence::date,\n ('NF-e ' || coalesce(v_doc.nfe_number, '?') || ' · ' || coalesce(v_doc.supplier_name, 'fornecedor'))::text,\n NULL::text,\n jsonb_build_object(\n 'source', 'danfe',\n 'danfe', jsonb_strip_nulls(jsonb_build_object(\n 'accessKey', v_doc.access_key, 'number', v_doc.nfe_number,\n 'series', v_doc.nfe_series, 'supplierName', v_doc.supplier_name,\n 'supplierCnpj', v_doc.supplier_cnpj,\n 'noteTotal', v_doc.total_value,\n 'inboxDocumentId', v_doc.id)))::jsonb,\n v_key::text);\n v_invoice := (v_inv->>'invoice_id')::uuid;\n\n INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)\n SELECT v_tenant, v_invoice, i.description, i.quantity_commercial, i.unit_price_commercial,\n round(coalesce(i.total_price, 0), 2), i.item_number,\n jsonb_strip_nulls(jsonb_build_object(\n 'itemKind', i.entry_type, 'referenceId', i.product_id,\n 'chartAccountId', i.chart_account_id, 'ncm', i.ncm, 'cfop', i.cfop,\n 'supplierProductCode', i.supplier_product_code))\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n ORDER BY i.item_number\n ON CONFLICT DO NOTHING;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n invoice_id = v_invoice,\n inventory_operation_id = coalesce((v_recv->>'operation_id')::uuid, inventory_operation_id),\n stocked_at = CASE WHEN v_stock_n > 0 THEN now() ELSE stocked_at END,\n status = 'accepted', updated_at = now()\n WHERE id = v_doc.id;\n\n INSERT INTO public.plg_fiscalbr_supplier_product_map (\n tenant_id, supplier_cnpj, supplier_product_code, product_id, entry_type,\n chart_account_id, stock_unit_id, conversion_factor, cost_mode, hit_count, last_used_at)\n SELECT v_tenant, v_doc.supplier_cnpj, i.supplier_product_code, i.product_id,\n i.entry_type, coalesce(i.chart_account_id, v_doc.default_chart_account_id),\n i.stock_unit_id, i.conversion_factor, i.cost_mode, 1, now()\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.product_id IS NOT NULL\n AND coalesce(v_doc.supplier_cnpj, '') <> ''\n AND coalesce(i.supplier_product_code, '') <> ''\n ON CONFLICT (tenant_id, supplier_cnpj, supplier_product_code) DO UPDATE SET\n product_id = EXCLUDED.product_id,\n entry_type = EXCLUDED.entry_type,\n chart_account_id = coalesce(EXCLUDED.chart_account_id, public.plg_fiscalbr_supplier_product_map.chart_account_id),\n stock_unit_id = coalesce(EXCLUDED.stock_unit_id, public.plg_fiscalbr_supplier_product_map.stock_unit_id),\n conversion_factor = EXCLUDED.conversion_factor,\n cost_mode = EXCLUDED.cost_mode,\n hit_count = public.plg_fiscalbr_supplier_product_map.hit_count + 1,\n last_used_at = now(),\n updated_at = now();\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'already_accepted', false,\n 'invoice_id', v_invoice, 'invoice_total', v_total,\n 'installments', jsonb_array_length(v_insts),\n 'operation_id', v_recv->>'operation_id',\n 'stock_lines', v_stock_n,\n 'movements', coalesce(v_recv->'movements', '[]'::jsonb));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) TO authenticated;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_preserve_terminal_results_and_recover_leases\", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },\n { id: \"002_a_nota_que_chega_tem_onde_esperar\", sql: MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR },\n { id: \"003_a_caixa_de_entrada_atravessa\", sql: MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA },\n { id: \"004_o_grupo_fiscal_do_v1_repete_nome\", sql: MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME },\n { id: \"005_a_nota_emitida_e_um_documento\", sql: MIGRATION_005_A_NOTA_EMITIDA_E_UM_DOCUMENTO },\n { id: \"006_o_grupo_fiscal_ganha_o_rail\", sql: MIGRATION_006_O_GRUPO_FISCAL_GANHA_O_RAIL },\n { id: \"007_a_rls_do_documento_passa_a_ser_legivel\", sql: MIGRATION_007_A_RLS_DO_DOCUMENTO_PASSA_A_SER_LEGIVEL },\n { id: \"008_a_nota_recebida_guarda_a_decisao_de_entrada\", sql: MIGRATION_008_A_NOTA_RECEBIDA_GUARDA_A_DECISAO_DE_ENTRADA },\n { id: \"009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez\", sql: MIGRATION_009_ACEITAR_A_NOTA_ESCREVE_ESTOQUE_E_TITULO_DE_UMA_VEZ },\n { id: \"010_a_data_de_emissao_e_instante_e_a_competencia_e_dia\", sql: MIGRATION_010_A_DATA_DE_EMISSAO_E_INSTANTE_E_A_COMPETENCIA_E_DIA },\n]\n","import type { EntityDef, PluginRegistryDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Grupos fiscais — a tributação que um produto herda.\n//\n// A tabela existe desde a 002 deste plugin e NUNCA teve tela: o grupo fiscal\n// de toda conta migrada estava no banco sem porta. Isto é a porta.\n//\n// O que ele responde é uma pergunta só, feita muitas vezes: com que imposto\n// este produto sai na nota. Agrupar é o ponto — sem grupo, CFOP, CST, origem e\n// três alíquotas seriam repetidos em cada produto, e mudar a regra de um\n// estado viraria uma edição em massa.\n//\n// A ordem dos campos segue a da nota: primeiro o que classifica a OPERAÇÃO\n// (CFOP), depois o ICMS, depois PIS/COFINS, e por último IBS/CBS — que é a\n// reforma tributária, e que já tem campo porque o V1 já tem.\n// ---------------------------------------------------------------------------\n\nconst taxGroupEntity: EntityDef = {\n name: 'Grupo fiscal',\n namePlural: 'Grupos fiscais',\n icon: 'ReceiptText',\n displayField: 'name',\n defaultSort: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [\n {\n id: 'identity', label: 'Identificação', columns: 2,\n description: 'O nome é como a casa chama o grupo («Bebida alcoólica», «Serviço isento») — o resto é o que a nota exige.',\n },\n { id: 'icms', label: 'ICMS', columns: 3 },\n { id: 'pis_cofins', label: 'PIS e COFINS', columns: 2 },\n {\n id: 'ibs_cbs', label: 'IBS e CBS', columns: 2,\n description: 'A reforma tributária. Em branco enquanto não for exigido da sua operação.',\n },\n { ...RECORD_GROUP },\n ],\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, searchable: true, group: 'identity', span: 2 },\n // O CFOP classifica a OPERAÇÃO (venda dentro do estado, fora, devolução) e\n // é o primeiro campo que o contador confere.\n { key: 'cfop', label: 'CFOP', type: 'text', showInTable: true, searchable: true, group: 'identity' },\n // CEST anda com a substituição tributária: só existe para quem está nela.\n { key: 'cest', label: 'CEST', type: 'text', showInTable: false, group: 'identity' },\n { key: 'benefitCode', label: 'Código de benefício', type: 'text', showInTable: false, group: 'identity' },\n\n // CST é do regime normal e CSOSN é do Simples — a casa usa UM dos dois, e\n // qual depende do regime dela, não deste grupo. Os dois ficam à vista de\n // propósito: esconder o que a conta não usa exigiria saber o regime aqui.\n { key: 'cst', label: 'CST', type: 'text', showInTable: true, group: 'icms' },\n { key: 'csosn', label: 'CSOSN (Simples)', type: 'text', showInTable: false, group: 'icms' },\n {\n key: 'icmsOrigin', label: 'Origem da mercadoria', type: 'select', showInTable: false, group: 'icms',\n options: [\n { value: '0', label: '0 — Nacional' },\n { value: '1', label: '1 — Estrangeira, importação direta' },\n { value: '2', label: '2 — Estrangeira, mercado interno' },\n { value: '3', label: '3 — Nacional, conteúdo de importação > 40%' },\n { value: '4', label: '4 — Nacional, processos produtivos básicos' },\n { value: '5', label: '5 — Nacional, conteúdo de importação ≤ 40%' },\n { value: '6', label: '6 — Estrangeira, sem similar nacional' },\n { value: '7', label: '7 — Estrangeira, mercado interno sem similar' },\n { value: '8', label: '8 — Nacional, conteúdo de importação > 70%' },\n ],\n },\n { key: 'icmsRate', label: 'Alíquota ICMS (%)', type: 'number', min: 0, max: 100, showInTable: true, group: 'icms' },\n { key: 'icmsBcMode', label: 'Modalidade da base', type: 'text', showInTable: false, group: 'icms' },\n { key: 'baseCalculationMode', label: 'Cálculo da base', type: 'text', showInTable: false, group: 'icms' },\n // O fundo de combate à pobreza é adicional ao ICMS em alguns estados.\n { key: 'povertyFundRate', label: 'Fundo de pobreza (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'icms' },\n\n { key: 'pisSituation', label: 'Situação PIS', type: 'text', showInTable: false, group: 'pis_cofins' },\n { key: 'pisRate', label: 'Alíquota PIS (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'pis_cofins' },\n { key: 'cofinsSituation', label: 'Situação COFINS', type: 'text', showInTable: false, group: 'pis_cofins' },\n { key: 'cofinsRate', label: 'Alíquota COFINS (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'pis_cofins' },\n\n { key: 'ibsCbsSituation', label: 'Situação IBS/CBS', type: 'text', showInTable: false, group: 'ibs_cbs' },\n { key: 'ibsCbsClassification', label: 'Classificação IBS/CBS', type: 'text', showInTable: false, group: 'ibs_cbs' },\n\n ...recordRailFields({ tagsTable: 'plg_fiscalbr_tax_groups', activeLabel: 'Ativo' }),\n ],\n data: {\n table: 'plg_fiscalbr_tax_groups',\n schema: 'public',\n tenantScoped: true,\n searchColumns: ['name', 'cfop'],\n },\n}\n\nexport const fiscalRegistries: PluginRegistryDef[] = [\n {\n id: 'taxGroups',\n icon: 'ReceiptText',\n entity: taxGroupEntity,\n description: 'A tributação que um produto herda: CFOP, ICMS, PIS/COFINS e, quando exigido, IBS/CBS.',\n agentHint: 'Regras de imposto que um produto herda — NÃO é a nota emitida nem o imposto de uma venda específica.',\n },\n]\n","// ---------------------------------------------------------------------------\n// nfe-xml — read a supplier NF-e (layout 4.00) into the shape the inbox wants.\n// ---------------------------------------------------------------------------\n// The XML is decomposed HERE, in TypeScript, and not in PL/pgSQL. Three reasons,\n// in order of how much each one cost when ignored elsewhere:\n//\n// 1. A parser with a unit test is a parser you can trust. The assertions in\n// nfe-xml.test.ts compare against what the V1 itself read out of the same\n// three documents, so drift is caught by the origin rather than by a number\n// someone typed into an expectation.\n// 2. A file that is not a nota has to produce a sentence the operator can act\n// on (\"this is an NFC-e, not a supplier note\"), and `RAISE EXCEPTION` from\n// a trigger deep in a transaction is not that sentence.\n// 3. The same reader runs in the browser, so the drop zone can show what it\n// found before anything is written.\n//\n// No XML dependency. The reader below is ~70 lines because NF-e is\n// machine-generated: no CDATA in the elements we read, no DTD, no mixed content.\n// Adding a parser to the dependency tree of every app that installs this plugin\n// to avoid those 70 lines is the worse trade.\n// ---------------------------------------------------------------------------\n\nexport interface NfeSupplier {\n cnpj: string\n name: string\n tradeName?: string\n ie?: string\n city?: string\n state?: string\n}\n\nexport interface NfeItem {\n itemNumber: number\n supplierProductCode: string\n eanBarcode?: string\n description: string\n ncm?: string\n cest?: string\n cfop?: string\n unit?: string\n quantity: number\n unitPrice: number\n total: number\n discount?: number\n freight?: number\n other?: number\n icmsCst?: string\n icmsCsosn?: string\n icmsOrigin?: string\n icmsBase?: number\n icmsRate?: number\n icmsValue?: number\n pisValue?: number\n cofinsValue?: number\n ipiValue?: number\n}\n\nexport interface NfeDuplicate {\n index: number\n number?: string\n dueDate?: string\n value: number\n}\n\nexport interface NfePayment {\n index: number\n indicator?: string\n code?: string\n label?: string\n value: number\n}\n\nexport interface NfeTotals {\n total: number\n products: number\n discount: number\n freight: number\n insurance: number\n other: number\n icmsBase?: number\n icmsValue?: number\n pisValue?: number\n cofinsValue?: number\n ipiValue?: number\n}\n\nexport interface ParsedNfe {\n accessKey: string\n nfeNumber: string\n nfeSeries: string\n nfeModel: string\n issueDate: string\n natureOperation?: string\n supplier: NfeSupplier\n totals: NfeTotals\n items: NfeItem[]\n duplicates: NfeDuplicate[]\n payments: NfePayment[]\n additionalInfo?: string\n protocol?: string\n authorizedAt?: string\n}\n\nexport class NfeParseError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'NfeParseError'\n }\n}\n\n// ── The reader ─────────────────────────────────────────────────────────────\n\ninterface XNode {\n name: string\n attrs: Record<string, string>\n children: XNode[]\n text: string\n}\n\nconst ENTITIES: Record<string, string> = {\n amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\",\n}\n\nfunction decode(raw: string): string {\n return raw.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (whole, body: string) => {\n if (body.startsWith('#x') || body.startsWith('#X')) return String.fromCodePoint(parseInt(body.slice(2), 16))\n if (body.startsWith('#')) return String.fromCodePoint(parseInt(body.slice(1), 10))\n return ENTITIES[body] ?? whole\n })\n}\n\n// Namespace prefixes are dropped: the whole document lives in the portalfiscal\n// namespace and a supplier that emits `ns2:infNFe` is emitting the same note.\nconst bare = (name: string) => {\n const i = name.indexOf(':')\n return i < 0 ? name : name.slice(i + 1)\n}\n\nfunction parseXml(xml: string): XNode {\n // Declaration, comments and processing instructions carry nothing we read.\n const src = xml\n .replace(/<\\?[\\s\\S]*?\\?>/g, '')\n .replace(/<!--[\\s\\S]*?-->/g, '')\n .replace(/<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>/g, (_m, inner: string) => inner)\n .replace(/<!DOCTYPE[^>]*>/gi, '')\n\n const root: XNode = { name: '#root', attrs: {}, children: [], text: '' }\n const stack: XNode[] = [root]\n const tag = /<\\s*(\\/?)\\s*([A-Za-z_][\\w.:-]*)((?:\\s+[\\w.:-]+\\s*=\\s*(?:\"[^\"]*\"|'[^']*'))*)\\s*(\\/?)\\s*>/g\n\n let cursor = 0\n let m: RegExpExecArray | null\n while ((m = tag.exec(src)) !== null) {\n const [whole, closing, rawName, rawAttrs, selfClosing] = m\n const top = stack[stack.length - 1]\n const between = src.slice(cursor, m.index)\n if (between.trim()) top.text += decode(between)\n cursor = m.index + whole.length\n\n if (closing) {\n if (stack.length > 1) stack.pop()\n continue\n }\n\n const attrs: Record<string, string> = {}\n const attrRe = /([\\w.:-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/g\n let a: RegExpExecArray | null\n while ((a = attrRe.exec(rawAttrs ?? '')) !== null) {\n attrs[bare(a[1])] = decode(a[2] ?? a[3] ?? '')\n }\n\n const node: XNode = { name: bare(rawName), attrs, children: [], text: '' }\n top.children.push(node)\n if (!selfClosing) stack.push(node)\n }\n return root\n}\n\nconst kids = (node: XNode | undefined, name: string): XNode[] =>\n node ? node.children.filter((c) => c.name === name) : []\n\nconst kid = (node: XNode | undefined, name: string): XNode | undefined => kids(node, name)[0]\n\n/** Walk a dot path (`ide.nNF`). Returns undefined at the first missing step. */\nfunction at(node: XNode | undefined, path: string): XNode | undefined {\n let cur = node\n for (const step of path.split('.')) {\n cur = kid(cur, step)\n if (!cur) return undefined\n }\n return cur\n}\n\nconst str = (node: XNode | undefined, path?: string): string | undefined => {\n const target = path ? at(node, path) : node\n const value = target?.text.trim()\n return value ? value : undefined\n}\n\n// The NF-e writes decimals with a dot and no thousands separator, so Number is\n// enough — but a missing tag must come back as undefined, not 0: a freight that\n// was not declared is not a freight of zero, and the difference shows up in the\n// total the payable is opened with.\nconst num = (node: XNode | undefined, path?: string): number | undefined => {\n const value = str(node, path)\n if (value === undefined) return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nconst zero = (node: XNode | undefined, path?: string): number => num(node, path) ?? 0\n\n// ── tPag → the V1's own payment vocabulary ─────────────────────────────────\n//\n// Table from NF-e 4.00 layout, collapsed onto the ten values V1 actually stores\n// (measured in `danfe_payments.payment_type`). Anything unmapped becomes\n// `outro`, which is what the V1 does with 107 of its 1.069 rows.\nconst PAYMENT_BY_CODE: Record<string, string> = {\n '01': 'dinheiro',\n '02': 'outro', // cheque\n '03': 'cartao_credito',\n '04': 'cartao_debito',\n '05': 'credito_loja',\n '10': 'outro', // vale alimentação\n '11': 'outro', // vale refeição\n '12': 'vale_presente',\n '13': 'outro', // vale combustível\n '14': 'duplicata_mercantil',\n '15': 'boleto',\n '16': 'outro', // depósito bancário\n '17': 'pix',\n '18': 'outro', // transferência bancária\n '19': 'outro', // programa de fidelidade\n '90': 'sem_pagamento',\n '99': 'outro',\n}\n\nconst PAYMENT_LABEL: Record<string, string> = {\n dinheiro: 'Dinheiro',\n cartao_credito: 'Cartão de crédito',\n cartao_debito: 'Cartão de débito',\n credito_loja: 'Crédito na loja',\n vale_presente: 'Vale presente',\n duplicata_mercantil: 'Duplicata mercantil',\n boleto: 'Boleto',\n pix: 'PIX',\n sem_pagamento: 'Sem pagamento',\n outro: 'Outro',\n}\n\n/** The V1's payment vocabulary for an NF-e `tPag` code. */\nexport function paymentTypeFromCode(code: string | undefined): string {\n if (!code) return 'outro'\n return PAYMENT_BY_CODE[code.padStart(2, '0')] ?? 'outro'\n}\n\nexport function paymentLabel(type: string): string {\n return PAYMENT_LABEL[type] ?? 'Outro'\n}\n\nexport const onlyDigits = (value: string | undefined): string => (value ?? '').replace(/\\D+/g, '')\n\n// ── The note ───────────────────────────────────────────────────────────────\n\n/**\n * Read a supplier NF-e. Accepts both the standalone `<NFe>` and the\n * `<nfeProc>` envelope the SEFAZ returns (which is what PlugNotas delivers and\n * what the V1 has stored for all 80 of Artorius' notes).\n */\nexport function parseNfeXml(xml: string): ParsedNfe {\n if (!xml || !xml.trim()) throw new NfeParseError('O arquivo está vazio.')\n\n const root = parseXml(xml)\n const proc = kid(root, 'nfeProc')\n const nfe = kid(proc ?? root, 'NFe') ?? kid(root, 'NFe')\n const inf = kid(nfe, 'infNFe')\n\n if (!inf) {\n throw new NfeParseError(\n 'Este arquivo não é uma NF-e: não encontrei <infNFe>. Se veio do fornecedor, peça o XML da nota, não o DANFE em PDF.',\n )\n }\n\n // The access key lives in the Id attribute as \"NFe\" + 44 digits. It is the\n // identity of the document — every idempotency key downstream derives from it.\n const accessKey = onlyDigits(inf.attrs.Id ?? inf.attrs.id ?? '')\n if (accessKey.length !== 44) {\n throw new NfeParseError(\n `A chave de acesso tem ${accessKey.length} dígitos e deveria ter 44. O arquivo pode estar truncado.`,\n )\n }\n\n const ide = kid(inf, 'ide')\n const model = str(ide, 'mod') ?? '55'\n if (model !== '55') {\n // 65 is NFC-e — a note the shop ISSUES at the till, not one a supplier sends.\n // Letting it through would open a payable against the shop's own customer.\n throw new NfeParseError(\n `Este XML é modelo ${model}${model === '65' ? ' (NFC-e, nota de venda no balcão)' : ''}, e a entrada de notas recebe NF-e modelo 55 de fornecedor.`,\n )\n }\n\n const emit = kid(inf, 'emit')\n const ender = kid(emit, 'enderEmit')\n const total = at(inf, 'total.ICMSTot')\n const dhEmi = str(ide, 'dhEmi') ?? str(ide, 'dEmi') ?? ''\n\n const items: NfeItem[] = kids(inf, 'det').map((det, i) => {\n const prod = kid(det, 'prod')\n const imposto = kid(det, 'imposto')\n // ICMS carries exactly one child, and which one depends on the supplier's tax\n // regime: ICMS00/20/40/60/90 for the normal regime, ICMSSN101/102/… for\n // Simples Nacional. Reading \"the child, whichever it is\" costs one line and\n // survives a supplier changing regime; a list of names does not.\n const icms = kid(imposto, 'ICMS')?.children[0]\n const pis = kid(imposto, 'PIS')?.children[0]\n const cofins = kid(imposto, 'COFINS')?.children[0]\n const ipi = kid(kid(imposto, 'IPI'), 'IPITrib')\n\n return {\n itemNumber: Number(det.attrs.nItem ?? i + 1) || i + 1,\n supplierProductCode: str(prod, 'cProd') ?? '',\n eanBarcode: str(prod, 'cEAN'),\n description: str(prod, 'xProd') ?? '(sem descrição)',\n ncm: str(prod, 'NCM'),\n cest: str(prod, 'CEST'),\n cfop: str(prod, 'CFOP'),\n unit: str(prod, 'uCom'),\n quantity: zero(prod, 'qCom'),\n unitPrice: zero(prod, 'vUnCom'),\n total: zero(prod, 'vProd'),\n discount: num(prod, 'vDesc'),\n freight: num(prod, 'vFrete'),\n other: num(prod, 'vOutro'),\n icmsCst: str(icms, 'CST'),\n icmsCsosn: str(icms, 'CSOSN'),\n icmsOrigin: str(icms, 'orig'),\n icmsBase: num(icms, 'vBC'),\n icmsRate: num(icms, 'pICMS'),\n icmsValue: num(icms, 'vICMS'),\n pisValue: num(pis, 'vPIS'),\n cofinsValue: num(cofins, 'vCOFINS'),\n ipiValue: num(ipi, 'vIPI'),\n }\n })\n\n if (items.length === 0) {\n throw new NfeParseError('A nota não tem nenhum item — não há o que dar entrada.')\n }\n\n // `cobr > dup` is the instalment plan the supplier declared. It is the reason\n // importing the note replaces typing the bill: the vencimentos come from the\n // document. A note without `dup` is not an error — it is paid on sight, and\n // the accept RPC opens a single instalment for it.\n const cobr = kid(inf, 'cobr')\n const duplicates: NfeDuplicate[] = kids(cobr, 'dup').map((dup, i) => ({\n index: i + 1,\n number: str(dup, 'nDup'),\n dueDate: str(dup, 'dVenc'),\n value: zero(dup, 'vDup'),\n }))\n\n const payments: NfePayment[] = kids(kid(inf, 'pag'), 'detPag').map((det, i) => {\n const code = str(det, 'tPag')\n const type = paymentTypeFromCode(code)\n return {\n index: i + 1,\n indicator: str(det, 'indPag'),\n code,\n label: paymentLabel(type),\n value: zero(det, 'vPag'),\n }\n })\n\n const prot = at(proc, 'protNFe.infProt')\n\n return {\n accessKey,\n nfeNumber: str(ide, 'nNF') ?? '',\n nfeSeries: str(ide, 'serie') ?? '',\n nfeModel: model,\n // The layout writes an ISO instant with offset; the inbox stores a date.\n issueDate: dhEmi.slice(0, 10),\n natureOperation: str(ide, 'natOp'),\n supplier: {\n cnpj: onlyDigits(str(emit, 'CNPJ') ?? str(emit, 'CPF')),\n name: str(emit, 'xNome') ?? '',\n tradeName: str(emit, 'xFant'),\n ie: str(emit, 'IE'),\n city: str(ender, 'xMun'),\n state: str(ender, 'UF'),\n },\n totals: {\n total: zero(total, 'vNF'),\n products: zero(total, 'vProd'),\n discount: zero(total, 'vDesc'),\n freight: zero(total, 'vFrete'),\n insurance: zero(total, 'vSeg'),\n other: zero(total, 'vOutro'),\n icmsBase: num(total, 'vBC'),\n icmsValue: num(total, 'vICMS'),\n pisValue: num(total, 'vPIS'),\n cofinsValue: num(total, 'vCOFINS'),\n ipiValue: num(total, 'vIPI'),\n },\n items,\n duplicates,\n payments,\n additionalInfo: str(at(inf, 'infAdic'), 'infCpl'),\n protocol: str(prot, 'nProt'),\n authorizedAt: str(prot, 'dhRecbto'),\n }\n}\n\n// ── The payload the staging RPC wants ──────────────────────────────────────\n//\n// `fiscalbr_stage_inbox_document` takes snake_case jsonb, and the mapping lives\n// next to the parser so a renamed field breaks in one place instead of being\n// silently dropped into a column that stays null.\n\nexport function toStagePayload(note: ParsedNfe, options: { unitId?: string | null; source?: string } = {}) {\n return {\n access_key: note.accessKey,\n nfe_number: note.nfeNumber,\n nfe_series: note.nfeSeries,\n nfe_model: note.nfeModel,\n issue_date: note.issueDate,\n nature_operation: note.natureOperation ?? null,\n additional_info: note.additionalInfo ?? null,\n unit_id: options.unitId ?? null,\n source: options.source ?? 'xml_upload',\n supplier: {\n cnpj: note.supplier.cnpj,\n name: note.supplier.name,\n ie: note.supplier.ie ?? null,\n },\n totals: {\n total: note.totals.total,\n products: note.totals.products,\n discount: note.totals.discount,\n freight: note.totals.freight,\n insurance: note.totals.insurance,\n other: note.totals.other,\n },\n items: note.items.map((i) => ({\n item_number: i.itemNumber,\n supplier_product_code: i.supplierProductCode,\n ean_barcode: i.eanBarcode ?? null,\n description: i.description,\n ncm: i.ncm ?? null,\n cest: i.cest ?? null,\n cfop: i.cfop ?? null,\n unit: i.unit ?? null,\n quantity: i.quantity,\n unit_price: i.unitPrice,\n total: i.total,\n discount: i.discount ?? null,\n freight: i.freight ?? null,\n other: i.other ?? null,\n icms_cst: i.icmsCst ?? null,\n icms_csosn: i.icmsCsosn ?? null,\n icms_base: i.icmsBase ?? null,\n icms_rate: i.icmsRate ?? null,\n icms_value: i.icmsValue ?? null,\n pis_value: i.pisValue ?? null,\n cofins_value: i.cofinsValue ?? null,\n ipi_value: i.ipiValue ?? null,\n })),\n // The instalment carries the payment form the note declared, so the\n // reconciliation dialog opens with `Boleto` already chosen instead of blank.\n duplicates: note.duplicates.map((d) => ({\n index: d.index,\n number: d.number ?? null,\n due_date: d.dueDate ?? null,\n value: d.value,\n payment_type: note.payments.length === 1 ? paymentTypeFromCode(note.payments[0].code) : null,\n })),\n payments: note.payments.map((p) => ({\n index: p.index,\n indicator: p.indicator ?? null,\n code: p.code ?? null,\n label: p.label ?? null,\n value: p.value,\n })),\n }\n}\n","// ---------------------------------------------------------------------------\n// inbox — the data layer of Entrada de Notas.\n// ---------------------------------------------------------------------------\n// Reads go through PostgREST so RLS answers; every WRITE goes through one of the\n// four RPCs of migration 009. That split is the whole safety property of this\n// screen: the browser never inserts a stock movement or a payable, it asks the\n// database to do both in one transaction with an idempotency key derived from\n// the NF-e access key.\n//\n// Nothing here parses XML. `../lib/nfe-xml` does that, is unit-tested against\n// three real notes, and hands this module the payload the staging RPC wants.\n// ---------------------------------------------------------------------------\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\nimport { parseNfeXml, toStagePayload, type ParsedNfe } from '../lib/nfe-xml'\nimport type {\n InboxNote, InboxNoteDetail, InboxItem, InboxInstalment,\n InboxStatusFilter, AcceptResult, StageResult, ProductOption,\n MeasurementUnitOption, ChartAccountOption, StockLocationOption,\n} from '../types'\n\nfunction sb() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\n// ── Leitura ────────────────────────────────────────────────────────────────\n\n// The two states the V1 list shows side by side, and they are NOT the same\n// question: `reconciled/total` counts items bound to a product, `stocked_at`\n// says the entry happened. 55 notes in the V1 were reconciled and never\n// stocked — a single \"status\" column would have hidden all 55.\nconst NOTE_COLUMNS = `\n id, access_key, nfe_number, nfe_series, issue_date, received_at, status,\n manifestation_status, manifested_at, manifestation_attempts,\n nature_operation, supplier_name, supplier_cnpj, supplier_party_id,\n total_value, total_products, total_discount, total_freight,\n invoice_id, inventory_operation_id, stocked_at, reviewed_at,\n default_chart_account_id, default_location_id, unit_id, document_id, metadata,\n items:plg_fiscalbr_inbox_items(id, reconciled, entry_type),\n duplicates:plg_fiscalbr_inbox_duplicates(id, value)\n`\n\ninterface RawNote {\n items?: Array<{ id: string; reconciled: boolean | null; entry_type: string | null }>\n duplicates?: Array<{ id: string; value: number | string | null }>\n [key: string]: unknown\n}\n\nfunction rowToNote(row: RawNote): InboxNote {\n const items = row.items ?? []\n const duplicates = row.duplicates ?? []\n return {\n id: String(row.id),\n accessKey: String(row.access_key ?? ''),\n number: String(row.nfe_number ?? ''),\n series: String(row.nfe_series ?? ''),\n issueDate: (row.issue_date as string) ?? null,\n receivedAt: (row.received_at as string) ?? null,\n status: (row.status as string) ?? 'pending',\n manifestationStatus: (row.manifestation_status as string) ?? null,\n manifestedAt: (row.manifested_at as string) ?? null,\n manifestationAttempts: Number(row.manifestation_attempts ?? 0),\n natureOperation: (row.nature_operation as string) ?? null,\n supplierName: (row.supplier_name as string) ?? '',\n supplierCnpj: (row.supplier_cnpj as string) ?? null,\n supplierPartyId: (row.supplier_party_id as string) ?? null,\n total: Number(row.total_value ?? 0),\n itemCount: items.length,\n reconciledCount: items.filter((i) => i.reconciled).length,\n instalmentCount: duplicates.length,\n // The sum of instalments, because that is the total the payable is opened\n // with (financial/084) — showing the note total here would make the list and\n // Contas a Pagar disagree on 6,3% of notes.\n instalmentTotal: duplicates.reduce((acc, d) => acc + Number(d.value ?? 0), 0),\n invoiceId: (row.invoice_id as string) ?? null,\n operationId: (row.inventory_operation_id as string) ?? null,\n stockedAt: (row.stocked_at as string) ?? null,\n documentId: (row.document_id as string) ?? null,\n unitId: (row.unit_id as string) ?? null,\n }\n}\n\nexport async function listInboxNotes(options: {\n filter?: InboxStatusFilter\n search?: string\n limit?: number\n} = {}): Promise<InboxNote[]> {\n const { filter = 'all', search, limit = 200 } = options\n let query = sb().from('plg_fiscalbr_inbox_documents').select(NOTE_COLUMNS)\n\n // `stocked` and `pending` are about the STOCK column, not about `status`:\n // \"pendente\" in the V1 list means the entry has not happened, whatever the\n // reconciliation says.\n if (filter === 'stocked') query = query.not('stocked_at', 'is', null)\n if (filter === 'pending') query = query.is('stocked_at', null)\n if (filter === 'rejected') query = query.eq('status', 'rejected')\n if (filter === 'to_manifest') query = query.not('manifestation_status', 'eq', 'confirmada')\n if (search?.trim()) {\n const term = search.trim()\n query = query.or(\n `supplier_name.ilike.%${term}%,nfe_number.ilike.%${term}%,access_key.ilike.%${term}%`,\n )\n }\n\n const { data, error } = await query\n .order('issue_date', { ascending: false, nullsFirst: false })\n .order('received_at', { ascending: false })\n .limit(limit)\n if (error) throw error\n return (data ?? []).map(rowToNote)\n}\n\nconst ITEM_COLUMNS = `\n id, item_number, supplier_product_code, ean_barcode, description, ncm, cest, cfop,\n unit_commercial, quantity_commercial, unit_price_commercial, total_price, discount,\n icms_cst, icms_csosn, icms_base, icms_rate, icms_value, pis_value, cofins_value, ipi_value,\n product_id, entry_type, chart_account_id, stock_unit_id, stock_quantity,\n conversion_factor, cost_mode, unit_cost_new, reconciled, stock_movement_id,\n shortage_quantity, shortage_reason, shortage_note\n`\n\nfunction rowToItem(row: Record<string, any>): InboxItem {\n const quantity = Number(row.quantity_commercial ?? 0)\n const factor = Number(row.conversion_factor ?? 1) || 1\n return {\n id: String(row.id),\n itemNumber: Number(row.item_number ?? 0),\n supplierProductCode: row.supplier_product_code ?? '',\n eanBarcode: row.ean_barcode ?? null,\n description: row.description ?? '',\n ncm: row.ncm ?? null,\n cest: row.cest ?? null,\n cfop: row.cfop ?? null,\n unit: row.unit_commercial ?? null,\n quantity,\n unitPrice: Number(row.unit_price_commercial ?? 0),\n total: Number(row.total_price ?? 0),\n discount: row.discount == null ? null : Number(row.discount),\n icmsCst: row.icms_cst ?? null,\n icmsCsosn: row.icms_csosn ?? null,\n icmsValue: row.icms_value == null ? null : Number(row.icms_value),\n productId: row.product_id ?? null,\n entryType: row.entry_type ?? null,\n chartAccountId: row.chart_account_id ?? null,\n stockUnitId: row.stock_unit_id ?? null,\n conversionFactor: factor,\n // Derived AND stored by the RPC. Reading the stored value keeps the screen\n // showing the number the operator accepted, and falls back to the product of\n // the two only while the decision has not been saved yet.\n stockQuantity: row.stock_quantity == null ? quantity * factor : Number(row.stock_quantity),\n costMode: row.cost_mode ?? 'novo',\n unitCostNew: row.unit_cost_new == null ? null : Number(row.unit_cost_new),\n reconciled: Boolean(row.reconciled),\n stockMovementId: row.stock_movement_id ?? null,\n shortageQuantity: row.shortage_quantity == null ? null : Number(row.shortage_quantity),\n shortageReason: row.shortage_reason ?? null,\n shortageNote: row.shortage_note ?? null,\n }\n}\n\nexport async function getInboxNote(id: string): Promise<InboxNoteDetail | null> {\n const { data, error } = await sb()\n .from('plg_fiscalbr_inbox_documents')\n .select(NOTE_COLUMNS)\n .eq('id', id)\n .maybeSingle()\n if (error) throw error\n if (!data) return null\n\n const [items, instalments, payments] = await Promise.all([\n sb().from('plg_fiscalbr_inbox_items').select(ITEM_COLUMNS)\n .eq('inbox_document_id', id).order('item_number'),\n sb().from('plg_fiscalbr_inbox_duplicates')\n .select('id, duplicate_index, number, due_date, value, payment_type, barcode, pix_key, payment_method_id')\n .eq('inbox_document_id', id).order('duplicate_index'),\n sb().from('plg_fiscalbr_inbox_payments')\n .select('id, payment_index, payment_type_code, payment_type_label, value')\n .eq('inbox_document_id', id).order('payment_index'),\n ])\n if (items.error) throw items.error\n if (instalments.error) throw instalments.error\n\n return {\n ...rowToNote(data as RawNote),\n natureOperation: (data as any).nature_operation ?? null,\n defaultChartAccountId: (data as any).default_chart_account_id ?? null,\n defaultLocationId: (data as any).default_location_id ?? null,\n items: (items.data ?? []).map(rowToItem),\n instalments: (instalments.data ?? []).map((d: any): InboxInstalment => ({\n id: String(d.id),\n index: Number(d.duplicate_index ?? 0),\n number: d.number ?? null,\n dueDate: d.due_date ?? null,\n amount: Number(d.value ?? 0),\n paymentType: d.payment_type ?? null,\n barcode: d.barcode ?? null,\n pixKey: d.pix_key ?? null,\n paymentMethodId: d.payment_method_id ?? null,\n })),\n declaredPayments: (payments.data ?? []).map((p: any) => ({\n index: Number(p.payment_index ?? 0),\n code: p.payment_type_code ?? null,\n label: p.payment_type_label ?? null,\n value: Number(p.value ?? 0),\n })),\n }\n}\n\n// ── Escrita: sempre por RPC ────────────────────────────────────────────────\n\n/**\n * Read one XML file and stage it. Returns what the parser found together with\n * how many items the de-para already bound, because that is the number the drop\n * zone reports: \"3 itens, 2 já vinculados\" is the difference between a screen\n * that remembers the supplier and one that does not.\n */\nexport async function stageNoteFromXml(\n xml: string,\n options: { unitId?: string | null } = {},\n): Promise<StageResult & { parsed: ParsedNfe }> {\n const parsed = parseNfeXml(xml)\n const { data, error } = await sb().rpc('fiscalbr_stage_inbox_document', {\n p_note: toStagePayload(parsed, { unitId: options.unitId ?? null }),\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n documentId: String(res.document_id ?? ''),\n accessKey: String(res.access_key ?? parsed.accessKey),\n alreadyAccepted: Boolean(res.already_accepted),\n supplierPartyId: (res.supplier_party_id as string) ?? null,\n itemCount: Number(res.items ?? 0),\n matchedCount: Number(res.matched ?? 0),\n parsed,\n }\n}\n\nexport interface ItemDecisionInput {\n id: string\n productId?: string | null\n entryType?: string | null\n chartAccountId?: string | null\n stockUnitId?: string | null\n conversionFactor?: number\n costMode?: string | null\n shortageQuantity?: number | null\n shortageReason?: string | null\n shortageNote?: string | null\n}\n\nexport interface InstalmentInput {\n index: number\n number?: string | null\n dueDate?: string | null\n amount: number\n paymentType?: string | null\n barcode?: string | null\n pixKey?: string | null\n paymentMethodId?: string | null\n}\n\nexport async function saveNoteDecision(input: {\n documentId: string\n items: ItemDecisionInput[]\n defaultChartAccountId?: string | null\n defaultLocationId?: string | null\n instalments?: InstalmentInput[] | null\n}): Promise<{ saved: number; items: number; reconciled: number }> {\n const { data, error } = await sb().rpc('fiscalbr_save_inbox_decision', {\n p_document_id: input.documentId,\n p_items: input.items.map((i) => ({\n id: i.id,\n product_id: i.productId ?? null,\n entry_type: i.entryType ?? null,\n chart_account_id: i.chartAccountId ?? null,\n stock_unit_id: i.stockUnitId ?? null,\n conversion_factor: i.conversionFactor ?? 1,\n cost_mode: i.costMode ?? 'novo',\n shortage_quantity: i.shortageQuantity ?? null,\n shortage_reason: i.shortageReason ?? null,\n shortage_note: i.shortageNote ?? null,\n })),\n p_default_chart_account_id: input.defaultChartAccountId ?? null,\n p_default_location_id: input.defaultLocationId ?? null,\n p_duplicates: input.instalments\n ? input.instalments.map((d) => ({\n index: d.index,\n number: d.number ?? null,\n due_date: d.dueDate ?? null,\n value: d.amount,\n payment_type: d.paymentType ?? null,\n barcode: d.barcode ?? null,\n pix_key: d.pixKey ?? null,\n payment_method_id: d.paymentMethodId ?? null,\n }))\n : null,\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n saved: Number(res.saved ?? 0),\n items: Number(res.items ?? 0),\n reconciled: Number(res.reconciled ?? 0),\n }\n}\n\n/**\n * Accept: stock entry and payable, one transaction. `alreadyAccepted` coming\n * back true is not an error — it is the second click, and the RPC is idempotent\n * on the NF-e access key.\n */\nexport async function acceptNote(documentId: string, locationId?: string | null): Promise<AcceptResult> {\n const { data, error } = await sb().rpc('fiscalbr_accept_inbox_document', {\n p_document_id: documentId,\n p_location_id: locationId ?? null,\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n documentId: String(res.document_id ?? documentId),\n alreadyAccepted: Boolean(res.already_accepted),\n invoiceId: (res.invoice_id as string) ?? null,\n invoiceTotal: Number(res.invoice_total ?? 0),\n instalments: Number(res.installments ?? 0),\n operationId: (res.operation_id as string) ?? null,\n stockLines: Number(res.stock_lines ?? 0),\n }\n}\n\nexport async function rejectNote(documentId: string, reason?: string): Promise<void> {\n const { error } = await sb().rpc('fiscalbr_reject_inbox_document', {\n p_document_id: documentId,\n p_reason: reason ?? null,\n })\n if (error) throw error\n}\n\n// ── Os cadastros que a conciliação precisa ─────────────────────────────────\n\nexport async function searchProducts(term: string, limit = 20): Promise<ProductOption[]> {\n let query = sb().from('products')\n .select('id, name, sku, unit, cost, kind')\n .eq('is_active', true)\n .limit(limit)\n if (term.trim()) query = query.or(`name.ilike.%${term.trim()}%,sku.ilike.%${term.trim()}%`)\n const { data, error } = await query.order('name')\n if (error) throw error\n return (data ?? []).map((p: any) => ({\n id: String(p.id), name: p.name ?? '', sku: p.sku ?? null,\n unit: p.unit ?? null, cost: p.cost == null ? null : Number(p.cost), kind: p.kind ?? null,\n }))\n}\n\nexport async function listMeasurementUnits(): Promise<MeasurementUnitOption[]> {\n const { data, error } = await sb().from('plg_inventory_measurement_units')\n .select('id, name, abbreviation, is_base').eq('is_active', true).order('name')\n if (error) throw error\n return (data ?? []).map((u: any) => ({\n id: String(u.id), name: u.name ?? '', abbreviation: u.abbreviation ?? '',\n isBase: Boolean(u.is_base),\n }))\n}\n\nexport async function listChartAccounts(): Promise<ChartAccountOption[]> {\n const { data, error } = await sb().from('plg_financial_chart_of_accounts')\n .select('id, code, name, kind, is_active').order('code')\n if (error) throw error\n return (data ?? [])\n .filter((a: any) => a.is_active !== false)\n .map((a: any) => ({\n id: String(a.id), code: a.code ?? '', name: a.name ?? '', kind: a.kind ?? null,\n }))\n}\n\nexport async function listStockLocations(): Promise<StockLocationOption[]> {\n const { data, error } = await sb().from('plg_inventory_stock_locations')\n .select('id, name, unit_id, is_active').order('name')\n if (error) throw error\n return (data ?? [])\n .filter((l: any) => l.is_active !== false)\n .map((l: any) => ({ id: String(l.id), name: l.name ?? '', unitId: l.unit_id ?? null }))\n}\n\n/**\n * What the supplier catalogue already remembers. The reconciliation screen shows\n * it next to a bound product so the operator can tell a de-para hit from a\n * product that appeared out of nowhere.\n */\nexport async function listSupplierMap(supplierCnpj: string): Promise<Array<{\n supplierProductCode: string; productId: string; hitCount: number; lastUsedAt: string | null\n}>> {\n if (!supplierCnpj) return []\n const { data, error } = await sb().from('plg_fiscalbr_supplier_product_map')\n .select('supplier_product_code, product_id, hit_count, last_used_at')\n .eq('supplier_cnpj', supplierCnpj)\n if (error) throw error\n return (data ?? []).map((m: any) => ({\n supplierProductCode: m.supplier_product_code ?? '',\n productId: String(m.product_id),\n hitCount: Number(m.hit_count ?? 0),\n lastUsedAt: m.last_used_at ?? null,\n }))\n}\n","// ---------------------------------------------------------------------------\n// Entrada de Notas — a lista, e a área onde o XML entra.\n// ---------------------------------------------------------------------------\n// Duas colunas de estado, e a diferença entre elas é o coração da tela:\n//\n// Conciliação quantos itens já sabem a que produto correspondem — 0/1, 1/1, 0/6\n// Estoque se a entrada aconteceu — Pendente / Estocado\n//\n// No V1 havia 55 notas conciliadas e nunca estocadas. Uma coluna de \"status\" só\n// teria escondido as 55, e a pergunta \"por que o estoque não mudou?\" não teria\n// resposta na tela.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { FileDown, Inbox, Loader2, Trash2, UploadCloud } from 'lucide-react'\nimport { Button, Card, Skeleton, ListFilterBar, PageHeaderActions } from '@fayz-ai/ui'\nimport { listInboxNotes, stageNoteFromXml, rejectNote } from '../data/inbox'\nimport type { InboxNote, InboxStatusFilter } from '../types'\n\nconst money = (value: number) =>\n new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value || 0)\n\nconst day = (iso: string | null) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\nconst cnpj = (digits: string | null) => {\n const d = (digits ?? '').replace(/\\D/g, '')\n if (d.length !== 14) return digits ?? '—'\n return `${d.slice(0, 2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${d.slice(12)}`\n}\n\n/** O resultado de arrastar um lote: o que entrou, o que o de-para já resolveu, o que recusou. */\ninterface DropReport {\n ok: Array<{ file: string; number: string; items: number; matched: number; repeated: boolean }>\n failed: Array<{ file: string; message: string }>\n}\n\nexport interface InboundNotesViewProps {\n /** Abre a conciliação da nota. A rota é do host — esta tela não sabe navegar. */\n onOpenNote: (noteId: string) => void\n onOpenManifest?: () => void\n}\n\nexport function InboundNotesView({ onOpenNote, onOpenManifest }: InboundNotesViewProps) {\n const [notes, setNotes] = useState<InboxNote[]>([])\n const [loading, setLoading] = useState(true)\n const [filter, setFilter] = useState<InboxStatusFilter>('all')\n const [busy, setBusy] = useState(false)\n const [report, setReport] = useState<DropReport | null>(null)\n const [dragging, setDragging] = useState(false)\n const fileInput = useRef<HTMLInputElement>(null)\n\n const reload = useCallback(async () => {\n setLoading(true)\n try {\n setNotes(await listInboxNotes({ filter }))\n } finally {\n setLoading(false)\n }\n }, [filter])\n\n useEffect(() => { void reload() }, [reload])\n\n // One file at a time, sequentially. The staging RPC is idempotent on the access\n // key, so a repeated file is not an error — but firing 20 of them in parallel\n // would race on the same de-para rows for the same supplier.\n const ingest = useCallback(async (files: File[]) => {\n const xmls = files.filter((f) => /\\.xml$/i.test(f.name))\n if (xmls.length === 0) {\n setReport({ ok: [], failed: [{ file: '—', message: 'Nenhum arquivo .xml no que foi solto.' }] })\n return\n }\n setBusy(true)\n const next: DropReport = { ok: [], failed: [] }\n for (const file of xmls) {\n try {\n const res = await stageNoteFromXml(await file.text())\n next.ok.push({\n file: file.name,\n number: res.parsed.nfeNumber,\n items: res.itemCount,\n matched: res.matchedCount,\n repeated: res.alreadyAccepted,\n })\n } catch (error) {\n next.failed.push({ file: file.name, message: error instanceof Error ? error.message : String(error) })\n }\n }\n setBusy(false)\n setReport(next)\n await reload()\n }, [reload])\n\n const remove = useCallback(async (note: InboxNote) => {\n // Recusar, não apagar: a nota é documento fiscal e continua legível.\n await rejectNote(note.id, 'Recusada na lista de entrada')\n await reload()\n }, [reload])\n\n const filters = useMemo(() => ([{\n id: 'estado',\n label: 'Estado',\n allLabel: 'Todos',\n value: filter === 'all' ? undefined : filter,\n onChange: (value: string | undefined) => setFilter((value as InboxStatusFilter) ?? 'all'),\n options: [\n { value: 'pending', label: 'Estoque pendente' },\n { value: 'stocked', label: 'Estocado' },\n { value: 'to_manifest', label: 'A manifestar' },\n { value: 'rejected', label: 'Recusada' },\n ],\n }]), [filter])\n\n return (\n <div className=\"space-y-4\">\n <PageHeaderActions>\n {onOpenManifest && (\n <Button variant=\"outline\" size=\"sm\" onClick={onOpenManifest}>\n <Inbox className=\"h-4 w-4 mr-1.5\" />\n Manifesto de Notas\n </Button>\n )}\n <Button size=\"sm\" onClick={() => fileInput.current?.click()} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 mr-1.5 animate-spin\" /> : <UploadCloud className=\"h-4 w-4 mr-1.5\" />}\n Importar XML\n </Button>\n </PageHeaderActions>\n\n {/* A área de arrastar é a porta de entrada, e o texto é o do V1: a entrada\n nasce do XML, não da digitação. */}\n <Card\n className={`border-dashed p-6 text-center transition-colors ${dragging ? 'border-primary bg-primary/5' : ''}`}\n onDragOver={(e: React.DragEvent) => { e.preventDefault(); setDragging(true) }}\n onDragLeave={() => setDragging(false)}\n onDrop={(e: React.DragEvent) => {\n e.preventDefault()\n setDragging(false)\n void ingest(Array.from(e.dataTransfer.files))\n }}\n >\n <UploadCloud className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Arraste arquivos XML aqui ou clique para selecionar</p>\n <p className=\"text-xs text-muted-foreground\">\n Suporta múltiplos arquivos XML de NF-e. O XML do fornecedor dá entrada no estoque e cria a conta a pagar.\n </p>\n <input\n ref={fileInput}\n type=\"file\"\n accept=\".xml,text/xml,application/xml\"\n multiple\n className=\"hidden\"\n onChange={(e) => {\n void ingest(Array.from(e.target.files ?? []))\n e.target.value = ''\n }}\n />\n </Card>\n\n {report && (\n <Card className=\"p-4 space-y-2\">\n {report.ok.map((r) => (\n <p key={r.file} className=\"text-sm\">\n <span className=\"font-medium\">NF-e {r.number}</span>{' '}\n <span className=\"text-muted-foreground\">\n {r.repeated\n ? '— já tinha sido aceita, nada mudou'\n // O número que diz se o de-para está trabalhando. Sem ele, o\n // operador não sabe se importar XML economizou algo.\n : `— ${r.items} ${r.items === 1 ? 'item' : 'itens'}, ${r.matched} já ${r.matched === 1 ? 'vinculado' : 'vinculados'}`}\n </span>\n </p>\n ))}\n {report.failed.map((r) => (\n <p key={r.file} className=\"text-sm text-destructive\">\n <span className=\"font-medium\">{r.file}</span> — {r.message}\n </p>\n ))}\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setReport(null)}>Fechar</Button>\n </Card>\n )}\n\n <ListFilterBar filters={filters} onClear={() => setFilter('all')} activeCount={filter === 'all' ? 0 : 1} />\n\n {loading ? (\n <div className=\"space-y-2\">\n {[0, 1, 2].map((i) => <Skeleton key={i} className=\"h-14 w-full\" />)}\n </div>\n ) : notes.length === 0 ? (\n <Card className=\"p-10 text-center\">\n <Inbox className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Nenhuma nota de entrada</p>\n <p className=\"text-xs text-muted-foreground\">\n As notas chegam da SEFAZ pelo Manifesto, ou você arrasta o XML aqui.\n </p>\n </Card>\n ) : (\n <Card className=\"overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead className=\"border-b bg-muted/40 text-xs text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2 text-left font-medium\">Emissão</th>\n <th className=\"px-3 py-2 text-left font-medium\">Nº</th>\n <th className=\"px-3 py-2 text-left font-medium\">Fornecedor</th>\n <th className=\"px-3 py-2 text-right font-medium\">Itens</th>\n <th className=\"px-3 py-2 text-center font-medium\">Conciliação</th>\n <th className=\"px-3 py-2 text-right font-medium\">Valor</th>\n <th className=\"px-3 py-2 text-center font-medium\">Estoque</th>\n <th className=\"px-3 py-2 text-right font-medium\">Ações</th>\n </tr>\n </thead>\n <tbody>\n {notes.map((note) => (\n <tr key={note.id} className=\"border-b last:border-0 hover:bg-muted/30\">\n <td className=\"px-3 py-2 tabular-nums text-muted-foreground\">{day(note.issueDate)}</td>\n <td className=\"px-3 py-2 tabular-nums font-medium\">{note.number}</td>\n <td className=\"px-3 py-2\">\n <p className=\"font-medium leading-tight\">{note.supplierName || '—'}</p>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{cnpj(note.supplierCnpj)}</p>\n </td>\n <td className=\"px-3 py-2 text-right tabular-nums text-muted-foreground\">{note.itemCount}</td>\n <td className=\"px-3 py-2 text-center\">\n <ReconcileBadge done={note.reconciledCount} total={note.itemCount} />\n </td>\n <td className=\"px-3 py-2 text-right tabular-nums\">\n {money(note.total)}\n {/* O título nasce com a soma das PARCELAS. Quando ela difere do\n total da nota, a tela mostra as duas — é a divergência que a\n conciliação passaria o mês procurando. */}\n {note.instalmentCount > 0 && Math.abs(note.instalmentTotal - note.total) > 0.01 && (\n <p className=\"text-[11px] text-warning-soft-foreground\">\n parcelas: {money(note.instalmentTotal)}\n </p>\n )}\n </td>\n <td className=\"px-3 py-2 text-center\">\n <StockBadge stockedAt={note.stockedAt} status={note.status} />\n </td>\n <td className=\"px-3 py-2\">\n <div className=\"flex justify-end gap-1\">\n <Button size=\"sm\" variant={note.stockedAt ? 'ghost' : 'outline'} onClick={() => onOpenNote(note.id)}>\n {note.stockedAt ? 'Ver' : 'Conciliar'}\n </Button>\n {!note.stockedAt && !note.invoiceId && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Recusar a nota ${note.number}`}\n onClick={() => { void remove(note) }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </Card>\n )}\n </div>\n )\n}\n\nfunction ReconcileBadge({ done, total }: { done: number; total: number }) {\n const full = total > 0 && done === total\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium tabular-nums ${\n full ? 'bg-success-soft text-success-soft-foreground' : 'bg-muted text-muted-foreground'\n }`}\n >\n {done}/{total}\n </span>\n )\n}\n\nfunction StockBadge({ stockedAt, status }: { stockedAt: string | null; status: string }) {\n if (status === 'rejected') {\n return <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground line-through\">Recusada</span>\n }\n return stockedAt ? (\n <span className=\"inline-flex items-center rounded-full bg-success-soft px-2 py-0.5 text-[11px] font-medium text-success-soft-foreground\">\n <FileDown className=\"mr-1 h-3 w-3\" aria-hidden />\n Estocado\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full bg-warning-soft px-2 py-0.5 text-[11px] font-medium text-warning-soft-foreground\">\n Pendente\n </span>\n )\n}\n","/** The preview contract deliberately excludes production emission. */\nexport type PlugNotasEnvironment = 'sandbox' | 'homologation'\nexport type PlugNotasDocumentStatus = 'draft' | 'processing' | 'issued' | 'cancelled' | 'error'\n\nexport interface PlugNotasSetupState {\n emitterCnpj: string\n environment: PlugNotasEnvironment\n certificateReady: boolean\n cscReady: boolean\n providerEmitterId?: string\n certificateExpiresAt?: string\n certificateFingerprint?: string\n}\n\nexport interface PlugNotasDocumentResult {\n status: PlugNotasDocumentStatus\n providerDocumentId?: string\n integrationId?: string\n number?: string\n series?: string\n accessKey?: string\n message?: string\n}\n\nexport interface PlugNotasFiscalGateway {\n issue(input: { notaId: string; idempotencyKey: string }): Promise<PlugNotasDocumentResult>\n refresh(input: { notaId: string }): Promise<PlugNotasDocumentResult>\n cancel(input: { notaId: string; reason: string }): Promise<PlugNotasDocumentResult>\n artifact(input: {\n notaId: string\n kind: 'xml' | 'pdf' | 'cancellation_xml'\n }): Promise<{ url: string }>\n}\n\nexport interface PlugNotasConnectorClient {\n testEmitter?(input: {\n emitterCnpj: string\n environment: PlugNotasEnvironment\n }): Promise<{ ok: boolean; message?: string }>\n disconnectEmitter?(): Promise<void>\n}\n\nexport interface PlugNotasFinancialProviderOptions {\n base: import('@fayz-ai/plugin-financial').FinancialDataProvider\n gateway: PlugNotasFiscalGateway\n}\n\n// ---------------------------------------------------------------------------\n// Entrada de Notas — a nota que o fornecedor emitiu contra o CNPJ da casa.\n// ---------------------------------------------------------------------------\n// Dois estados, e eles NÃO respondem à mesma pergunta. `reconciledCount/itemCount`\n// diz quantos itens já sabem a que produto correspondem; `stockedAt` diz se a\n// entrada aconteceu. No V1 havia 55 notas conciliadas e nunca estocadas — uma\n// coluna de \"status\" só teria escondido as 55.\n\n/** Os cinco tipos de registro do V1, medidos em 3.402 linhas de produção. */\nexport type InboxEntryType = 'insumo' | 'revenda' | 'patrimonio' | 'despesa' | 'servico'\n\n/** Despesa e serviço nunca viram estoque: viram só título a pagar. */\nexport const STOCK_BEARING_ENTRY_TYPES: readonly InboxEntryType[] = ['insumo', 'revenda', 'patrimonio']\n\nexport const isStockBearing = (type: string | null | undefined): boolean =>\n STOCK_BEARING_ENTRY_TYPES.includes(type as InboxEntryType)\n\nexport type InboxCostMode = 'novo' | 'media'\n\nexport type InboxStatusFilter = 'all' | 'pending' | 'stocked' | 'rejected' | 'to_manifest'\n\nexport interface InboxNote {\n id: string\n accessKey: string\n number: string\n series: string\n issueDate: string | null\n receivedAt: string | null\n status: string\n manifestationStatus: string | null\n manifestedAt: string | null\n manifestationAttempts: number\n natureOperation: string | null\n supplierName: string\n supplierCnpj: string | null\n supplierPartyId: string | null\n /** O total declarado na NOTA. */\n total: number\n itemCount: number\n reconciledCount: number\n instalmentCount: number\n /** A soma das PARCELAS — é com este total que o título nasce (financial/084). */\n instalmentTotal: number\n invoiceId: string | null\n operationId: string | null\n stockedAt: string | null\n documentId: string | null\n unitId: string | null\n}\n\nexport interface InboxItem {\n id: string\n itemNumber: number\n supplierProductCode: string\n eanBarcode: string | null\n description: string\n ncm: string | null\n cest: string | null\n cfop: string | null\n unit: string | null\n quantity: number\n unitPrice: number\n total: number\n discount: number | null\n icmsCst: string | null\n icmsCsosn: string | null\n icmsValue: number | null\n productId: string | null\n entryType: string | null\n chartAccountId: string | null\n stockUnitId: string | null\n conversionFactor: number\n /** Quantidade × fator, menos a falta. É o número que a tela mostra ANTES de aceitar. */\n stockQuantity: number\n costMode: string\n unitCostNew: number | null\n reconciled: boolean\n stockMovementId: string | null\n shortageQuantity: number | null\n shortageReason: string | null\n shortageNote: string | null\n}\n\nexport interface InboxInstalment {\n id: string\n index: number\n number: string | null\n dueDate: string | null\n amount: number\n paymentType: string | null\n barcode: string | null\n pixKey: string | null\n paymentMethodId: string | null\n}\n\nexport interface InboxNoteDetail extends InboxNote {\n defaultChartAccountId: string | null\n defaultLocationId: string | null\n items: InboxItem[]\n instalments: InboxInstalment[]\n /** `pag > detPag` do XML: o que o fornecedor DECLAROU, não o que se decidiu. */\n declaredPayments: Array<{ index: number; code: string | null; label: string | null; value: number }>\n}\n\nexport interface StageResult {\n documentId: string\n accessKey: string\n alreadyAccepted: boolean\n supplierPartyId: string | null\n itemCount: number\n /** Quantos itens o de-para do fornecedor já vinculou sozinho. */\n matchedCount: number\n}\n\nexport interface AcceptResult {\n documentId: string\n /** `true` é o segundo clique, não um erro: a RPC é idempotente na chave de acesso. */\n alreadyAccepted: boolean\n invoiceId: string | null\n invoiceTotal: number\n instalments: number\n operationId: string | null\n stockLines: number\n}\n\nexport interface ProductOption {\n id: string\n name: string\n sku: string | null\n unit: string | null\n cost: number | null\n kind: string | null\n}\n\nexport interface MeasurementUnitOption {\n id: string\n name: string\n abbreviation: string\n isBase: boolean\n}\n\nexport interface ChartAccountOption {\n id: string\n code: string\n name: string\n kind: string | null\n}\n\nexport interface StockLocationOption {\n id: string\n name: string\n unitId: string | null\n}\n","// ---------------------------------------------------------------------------\n// Conciliação — onde a nota do fornecedor vira estoque e dinheiro.\n// ---------------------------------------------------------------------------\n// Os quatro blocos do V1, na mesma ordem: situação fiscal · itens · pagamento ·\n// anexos. O que mudou de forma, e por quê:\n//\n// O V1 põe isto num DIÁLOGO. Um diálogo com quatro blocos e uma grade de duas\n// colunas por item vira rolagem dentro de rolagem, e o item de baixo some\n// atrás do rodapé com «Aceitar» — exatamente o gesto que não pode ser dado no\n// escuro. Aqui é SUBPÁGINA, com `SubpageHeader` e «← Voltar», que é o idioma do\n// V2 para um fluxo inteiro. Mesma capacidade, mesma ordem, mesmo rodapé.\n//\n// A regra que a tela existe para cumprir: a **Qtd estoque (calc.)** muda na tela\n// ANTES de aceitar. O FLOW.md do V1 diz que fator de conversão errado é\n// silencioso e que esse número é a única defesa.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { AlertTriangle, Check, Gift, Loader2, Plus, RefreshCw, Trash2, X } from 'lucide-react'\nimport { EmBreve } from './ComingSoon'\nimport {\n Button, Card, Input, SearchSelect, Skeleton, SubpageHeader, DatePicker, Hint,\n} from '@fayz-ai/ui'\nimport {\n getInboxNote, saveNoteDecision, acceptNote, rejectNote,\n searchProducts, listMeasurementUnits, listChartAccounts, listStockLocations,\n type ItemDecisionInput, type InstalmentInput,\n} from '../data/inbox'\nimport type { SearchSelectOption } from '@fayz-ai/ui'\nimport type {\n InboxNoteDetail, InboxItem, InboxEntryType,\n MeasurementUnitOption, ChartAccountOption, StockLocationOption, AcceptResult,\n} from '../types'\nimport { isStockBearing } from '../types'\n\nconst money = (v: number) => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(v || 0)\nconst qty = (v: number) => new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 4 }).format(v || 0)\nconst day = (iso: string | null | undefined) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\n// O vocabulário é o do V1, e a ordem é a de uso: insumo é 2.303 das 3.402 linhas.\nconst ENTRY_TYPES: Array<{ value: InboxEntryType; label: string; hint?: string }> = [\n { value: 'insumo', label: 'Insumo' },\n { value: 'revenda', label: 'Produto Revenda' },\n { value: 'patrimonio', label: 'Patrimônio' },\n { value: 'despesa', label: 'Despesa', hint: 'não vira estoque' },\n { value: 'servico', label: 'Serviço', hint: 'não vira estoque' },\n]\n\n/** O estado editável de uma linha. Espelha `ItemDecisionInput`, mais o que a tela calcula. */\ninterface Draft {\n productId: string | null\n productLabel: string\n entryType: InboxEntryType | null\n chartAccountId: string | null\n stockUnitId: string | null\n conversionFactor: string\n costMode: 'novo' | 'media'\n shortageQuantity: string\n}\n\n/**\n * `SearchSelect` não tem prop `options`: ele é sempre dirigido por busca — o que é\n * a escolha certa para produto (o catálogo tem 171) e continua servindo para as\n * listas curtas (plano de contas, unidade, local), filtrando em memória.\n */\nconst localSearch = (options: SearchSelectOption[]) => (query: string): SearchSelectOption[] => {\n const q = query.trim().toLowerCase()\n return (q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options).slice(0, 40)\n}\n\nconst labelOf = (options: SearchSelectOption[], id: string | null | undefined) =>\n options.find((o) => o.id === id)?.label\n\nconst draftOf = (item: InboxItem): Draft => ({\n productId: item.productId,\n productLabel: '',\n entryType: (item.entryType as InboxEntryType) ?? null,\n chartAccountId: item.chartAccountId,\n stockUnitId: item.stockUnitId,\n conversionFactor: String(item.conversionFactor ?? 1),\n costMode: (item.costMode === 'media' ? 'media' : 'novo'),\n shortageQuantity: item.shortageQuantity == null ? '' : String(item.shortageQuantity),\n})\n\nexport interface NoteReconcileViewProps {\n noteId: string\n onBack: () => void\n /** Onde o título a pagar abre depois de aceitar. O host sabe a rota; esta tela não. */\n onOpenInvoice?: (invoiceId: string) => void\n}\n\nexport function NoteReconcileView({ noteId, onBack, onOpenInvoice }: NoteReconcileViewProps) {\n const [note, setNote] = useState<InboxNoteDetail | null>(null)\n const [loading, setLoading] = useState(true)\n const [drafts, setDrafts] = useState<Record<string, Draft>>({})\n const [instalments, setInstalments] = useState<InstalmentInput[]>([])\n const [defaultAccount, setDefaultAccount] = useState<string | null>(null)\n const [location, setLocation] = useState<string | null>(null)\n const [units, setUnits] = useState<MeasurementUnitOption[]>([])\n const [accounts, setAccounts] = useState<ChartAccountOption[]>([])\n const [locations, setLocations] = useState<StockLocationOption[]>([])\n const [saving, setSaving] = useState(false)\n const [accepting, setAccepting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [accepted, setAccepted] = useState<AcceptResult | null>(null)\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n // A NOTA primeiro, e sozinha. Juntar tudo num `Promise.all` fazia a tela\n // MENTIR: bastava um dos três cadastros falhar para a promessa rejeitar, a\n // nota nunca ser atribuída, e a tela dizer «Nota não encontrada» sobre uma\n // nota que está lá. Foi o que aconteceu no primeiro E2E — a nota existia,\n // a consulta dela respondia 200, e a tela dizia que não existia.\n const detail = await getInboxNote(noteId)\n setNote(detail)\n\n // Os cadastros são para PREENCHER os seletores. Um que não carrega deixa um\n // seletor vazio — que é ruim, e é visível — em vez de esconder a nota.\n const [u, a, l] = await Promise.all([\n listMeasurementUnits().catch(() => [] as MeasurementUnitOption[]),\n listChartAccounts().catch(() => [] as ChartAccountOption[]),\n listStockLocations().catch(() => [] as StockLocationOption[]),\n ])\n setUnits(u); setAccounts(a); setLocations(l)\n if (detail) {\n setDrafts(Object.fromEntries(detail.items.map((i) => [i.id, draftOf(i)])))\n setInstalments(detail.instalments.map((d) => ({\n index: d.index, number: d.number, dueDate: d.dueDate, amount: d.amount,\n paymentType: d.paymentType, barcode: d.barcode, pixKey: d.pixKey,\n })))\n setDefaultAccount(detail.defaultChartAccountId)\n setLocation(detail.defaultLocationId ?? l[0]?.id ?? null)\n }\n } catch (e) {\n // Falhar buscando a nota é diferente de não achar a nota, e a tela tem de\n // dizer qual dos dois foi.\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setLoading(false)\n }\n }, [noteId])\n\n useEffect(() => { void load() }, [load])\n\n const patch = (id: string, change: Partial<Draft>) =>\n setDrafts((prev) => ({ ...prev, [id]: { ...prev[id], ...change } }))\n\n const accountOptions = useMemo<SearchSelectOption[]>(\n () => accounts.map((a) => ({ id: a.id, label: `${a.code} · ${a.name}` })),\n [accounts],\n )\n const unitOptions = useMemo<SearchSelectOption[]>(\n () => units.map((u) => ({ id: u.id, label: u.abbreviation, subtitle: u.name })),\n [units],\n )\n const locationOptions = useMemo<SearchSelectOption[]>(\n () => locations.map((l) => ({ id: l.id, label: l.name })),\n [locations],\n )\n\n const decisions = useMemo((): ItemDecisionInput[] => {\n if (!note) return []\n return note.items.map((item) => {\n const d = drafts[item.id] ?? draftOf(item)\n return {\n id: item.id,\n productId: isStockBearing(d.entryType) ? d.productId : null,\n entryType: d.entryType,\n // A herança que a legenda do V1 promete: «itens sem plano herdarão este».\n chartAccountId: d.chartAccountId ?? defaultAccount,\n stockUnitId: d.stockUnitId,\n conversionFactor: Number(d.conversionFactor.replace(',', '.')) || 1,\n costMode: d.costMode,\n shortageQuantity: d.shortageQuantity === '' ? null : Number(d.shortageQuantity.replace(',', '.')),\n }\n })\n }, [note, drafts, defaultAccount])\n\n const stockLines = decisions.filter((d) => isStockBearing(d.entryType))\n const missingProduct = stockLines.filter((d) => !d.productId).length\n const missingType = decisions.filter((d) => !d.entryType).length\n const instalmentSum = instalments.reduce((acc, d) => acc + (Number(d.amount) || 0), 0)\n const readOnly = Boolean(note?.stockedAt || note?.invoiceId)\n\n const save = async () => {\n if (!note) return\n setSaving(true); setError(null)\n try {\n await saveNoteDecision({\n documentId: note.id, items: decisions,\n defaultChartAccountId: defaultAccount, defaultLocationId: location,\n instalments,\n })\n await load()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setSaving(false)\n }\n }\n\n const accept = async () => {\n if (!note) return\n setAccepting(true); setError(null)\n try {\n // Salvar e aceitar num gesto: o operador clicou «Aceitar», e pedir que ele\n // salve antes seria uma etapa que só existe por causa do nosso desenho.\n await saveNoteDecision({\n documentId: note.id, items: decisions,\n defaultChartAccountId: defaultAccount, defaultLocationId: location,\n instalments,\n })\n setAccepted(await acceptNote(note.id, location))\n await load()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setAccepting(false)\n }\n }\n\n if (loading) {\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title=\"Conciliação\" onBack={onBack} parentLabel=\"Entrada de Notas\" />\n <Skeleton className=\"h-24 w-full\" />\n <Skeleton className=\"h-48 w-full\" />\n </div>\n )\n }\n\n if (!note) {\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title=\"Conciliação\" onBack={onBack} parentLabel=\"Entrada de Notas\" />\n <Card className=\"p-8 text-center text-sm\">\n {error\n ? <span className=\"text-destructive\">Não consegui carregar a nota: {error}</span>\n : <span className=\"text-muted-foreground\">Nota não encontrada.</span>}\n </Card>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4 pb-24\">\n <SubpageHeader\n title={`Conciliação · NF-e ${note.number}`}\n onBack={onBack}\n parentLabel=\"Entrada de Notas\"\n />\n\n {accepted && (\n <Card className=\"border-success bg-success-soft p-4\">\n <p className=\"text-sm font-medium text-success-soft-foreground\">\n {accepted.alreadyAccepted\n ? 'Esta nota já havia sido aceita — nada foi lançado de novo.'\n : `Aceita: ${accepted.stockLines} ${accepted.stockLines === 1 ? 'linha' : 'linhas'} de estoque e um título de ${money(accepted.invoiceTotal)} em ${accepted.instalments} ${accepted.instalments === 1 ? 'parcela' : 'parcelas'}.`}\n </p>\n {accepted.invoiceId && onOpenInvoice && (\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => onOpenInvoice(accepted.invoiceId!)}>\n Abrir a conta a pagar\n </Button>\n )}\n </Card>\n )}\n\n {/* ── 1. Situação fiscal ─────────────────────────────────────────── */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Situação fiscal</h3>\n <dl className=\"mt-3 grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2 lg:grid-cols-3\">\n <Field label=\"Fornecedor\" value={note.supplierName || '—'} />\n <Field label=\"CNPJ\" value={note.supplierCnpj ?? '—'} mono />\n <Field label=\"Natureza da operação\" value={note.natureOperation ?? '—'} />\n <Field\n label=\"Manifestação\"\n value={`${note.manifestationStatus ?? 'não manifestada'}${note.manifestationAttempts ? ` · ${note.manifestationAttempts} tentativa(s)` : ''}`}\n />\n <Field label=\"Manifestada em\" value={day(note.manifestedAt)} />\n <Field label=\"Recebida em\" value={day(note.receivedAt)} />\n </dl>\n {/* O aviso é um bloco, não um trecho de texto: solto ele vazava do card e\n empurrava o botão para debaixo da própria frase. */}\n {!note.supplierPartyId && (\n <div className=\"mt-3 rounded-md border border-warning bg-warning-soft px-3 py-2\">\n <p className=\"text-xs text-warning-soft-foreground\">\n Este fornecedor não está no cadastro de pessoas, então o título a pagar vai nascer{' '}\n <strong>sem contraparte</strong>. Cadastre o CNPJ antes de aceitar para a conta saber a\n quem se deve.\n </p>\n </div>\n )}\n {/* A nota de bonificação entra no estoque e NÃO deve gerar título. Hoje\n gera: 57 notas assim no V1 da Artorius, em 11 grafias de natureza. */}\n {/bonific|brinde|doacao|doação/i.test(note.natureOperation ?? '') && (\n <div className=\"mt-3 rounded-md border border-dashed border-input px-3 py-2\">\n <p className=\"text-xs text-muted-foreground\">\n <Gift className=\"mr-1 inline h-3.5 w-3.5\" aria-hidden />\n A natureza desta nota é <strong>bonificação</strong>. Ela deveria entrar no estoque{' '}\n <strong>sem</strong> abrir conta a pagar — hoje ainda abre.{' '}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-[10px]\">Em breve</span>\n </p>\n </div>\n )}\n\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={() => { void load() }}>\n <RefreshCw className=\"mr-1.5 h-4 w-4\" />\n Atualizar status\n </Button>\n <EmBreve\n label=\"Cadastrar fornecedor\"\n o_que=\"Criar a pessoa do fornecedor aqui, sem sair da nota — é o que preenche a contraparte do título\"\n quantas=\"a Laissa cadastrou 37 fornecedores no V1 enquanto importava\"\n />\n </div>\n </Card>\n\n {/* ── 2. Padrões da nota ─────────────────────────────────────────── */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Padrões desta nota</h3>\n <div className=\"mt-3 grid gap-4 sm:grid-cols-2\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Plano de contas padrão</span>\n <SearchSelect\n onSearch={localSearch(accountOptions)}\n value={defaultAccount ?? undefined}\n displayValue={labelOf(accountOptions, defaultAccount)}\n onChange={(id) => setDefaultAccount(id || null)}\n minChars={0}\n placeholder=\"Escolher plano de contas\"\n noResultsLabel=\"Nenhum plano de contas\"\n searchingLabel=\"Buscando…\"\n disabled={readOnly}\n />\n <span className=\"mt-1 block text-[11px] text-muted-foreground\">\n Itens sem plano herdarão este.\n </span>\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Local de estoque</span>\n <SearchSelect\n onSearch={localSearch(locationOptions)}\n value={location ?? undefined}\n displayValue={labelOf(locationOptions, location)}\n onChange={(id) => setLocation(id || null)}\n minChars={0}\n placeholder=\"Escolher local\"\n noResultsLabel=\"Nenhum local de estoque\"\n searchingLabel=\"Buscando…\"\n disabled={readOnly}\n />\n <span className=\"mt-1 block text-[11px] text-muted-foreground\">\n Onde as linhas de estoque desta nota entram.\n </span>\n </label>\n </div>\n </Card>\n\n {/* ── 3. Itens ───────────────────────────────────────────────────── */}\n <div className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">\n Itens <span className=\"font-normal text-muted-foreground\">({note.items.length})</span>\n </h3>\n {note.items.map((item) => {\n const d = drafts[item.id] ?? draftOf(item)\n const factor = Number(d.conversionFactor.replace(',', '.')) || 1\n const shortage = d.shortageQuantity === '' ? 0 : Number(d.shortageQuantity.replace(',', '.')) || 0\n const stockQty = item.quantity * factor - shortage\n const unitCost = factor > 0 ? item.unitPrice / factor : item.unitPrice\n const bearing = isStockBearing(d.entryType)\n\n return (\n <Card key={item.id} className=\"p-4\">\n <div className=\"grid gap-4 lg:grid-cols-2\">\n {/* ITEM NA NOTA — o que o documento diz, e não se edita. */}\n <div>\n <p className=\"text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Item na nota\n </p>\n <p className=\"mt-1 font-medium leading-tight\">{item.itemNumber}. {item.description}</p>\n <dl className=\"mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs sm:grid-cols-4\">\n <Field small label=\"Qtd\" value={`${qty(item.quantity)} ${item.unit ?? ''}`} />\n <Field small label=\"Vl. unit.\" value={money(item.unitPrice)} />\n <Field small label=\"Total\" value={money(item.total)} />\n <Field small label=\"Cód\" value={item.supplierProductCode || '—'} mono />\n <Field small label=\"EAN\" value={item.eanBarcode ?? '—'} mono />\n <Field small label=\"NCM\" value={item.ncm ?? '—'} mono />\n <Field small label=\"CFOP\" value={item.cfop ?? '—'} mono />\n <Field small label=\"CST/CSOSN\" value={item.icmsCst ?? item.icmsCsosn ?? '—'} mono />\n </dl>\n </div>\n\n {/* ITEM NO ESTOQUE — a decisão. */}\n <div className=\"space-y-3 lg:border-l lg:pl-4\">\n <p className=\"text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Item no estoque\n </p>\n\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Tipo do registro</span>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {ENTRY_TYPES.map((t) => (\n <button\n key={t.value}\n type=\"button\"\n disabled={readOnly}\n onClick={() => patch(item.id, { entryType: t.value })}\n className={`rounded-full border px-2.5 py-1 text-[11px] transition-colors disabled:opacity-60 ${\n d.entryType === t.value\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-input hover:bg-muted'\n }`}\n >\n {t.label}\n {t.hint && <span className=\"ml-1 opacity-70\">· {t.hint}</span>}\n </button>\n ))}\n </div>\n </label>\n\n {bearing && (\n <>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Produto vinculado</span>\n <SearchSelect\n value={d.productId ?? undefined}\n displayValue={d.productLabel || undefined}\n onChange={(id, option) =>\n patch(item.id, { productId: id || null, productLabel: option?.label ?? '' })}\n onSearch={async (term: string) => {\n // Busca vazia traz o que mais se parece com a descrição da\n // nota: o operador quase sempre quer justamente aquilo.\n const found = await searchProducts(term || item.description.slice(0, 24))\n return found.map((prod) => ({\n id: prod.id,\n label: prod.name,\n subtitle: prod.sku ?? undefined,\n }))\n }}\n minChars={0}\n placeholder=\"Buscar produto do catálogo\"\n noResultsLabel=\"Nenhum produto encontrado\"\n searchingLabel=\"Buscando…\"\n disabled={readOnly}\n />\n </label>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Fator de conversão</span>\n <Input\n value={d.conversionFactor}\n onChange={(e) => patch(item.id, { conversionFactor: e.target.value })}\n inputMode=\"decimal\"\n disabled={readOnly}\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Unidade de estoque</span>\n <SearchSelect\n onSearch={localSearch(unitOptions)}\n value={d.stockUnitId ?? undefined}\n displayValue={labelOf(unitOptions, d.stockUnitId)}\n onChange={(id) => patch(item.id, { stockUnitId: id || null })}\n minChars={0}\n placeholder=\"Unidade\"\n noResultsLabel=\"Nenhuma unidade\"\n searchingLabel=\"Buscando…\"\n disabled={readOnly}\n />\n </label>\n </div>\n\n {/* A única defesa contra fator errado, e ela tem de ser\n legível ANTES de aceitar. */}\n <div className=\"rounded-md bg-muted/50 px-3 py-2\">\n <div className=\"flex items-baseline justify-between text-sm\">\n <span className=\"text-xs text-muted-foreground\">Qtd estoque (calc.)</span>\n <span className=\"font-semibold tabular-nums\">{qty(stockQty)}</span>\n </div>\n <div className=\"flex items-baseline justify-between text-sm\">\n <span className=\"text-xs text-muted-foreground\">Novo custo unitário</span>\n <span className=\"tabular-nums\">{money(unitCost)}</span>\n </div>\n </div>\n\n {/* Os dois gestos que hoje mandam a Laissa sair da tela. */}\n <div className=\"flex flex-wrap gap-2\">\n <EmBreve\n label=\"Criar produto daqui\"\n o_que=\"Cadastrar o produto a partir desta linha da nota, com nome, código e unidade já preenchidos\"\n quantas=\"ela criou 33 produtos no V1 no meio de importações\"\n />\n <EmBreve\n label=\"Lote e validade\"\n o_que=\"Informar lote e vencimento desta entrada — a coluna já existe no movimento de estoque\"\n quantas=\"usado 5 vezes no V1; numa churrascaria é validade de carne\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Modo de custo</span>\n <div className=\"mt-1 flex gap-1\">\n {(['novo', 'media'] as const).map((mode) => (\n <button\n key={mode}\n type=\"button\"\n disabled={readOnly}\n onClick={() => patch(item.id, { costMode: mode })}\n className={`flex-1 rounded-md border px-2 py-1 text-[11px] disabled:opacity-60 ${\n d.costMode === mode ? 'border-primary bg-primary/10' : 'border-input hover:bg-muted'\n }`}\n >\n {mode === 'novo' ? 'Novo' : 'Média'}\n </button>\n ))}\n </div>\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Falta (qtd)</span>\n <Input\n value={d.shortageQuantity}\n onChange={(e) => patch(item.id, { shortageQuantity: e.target.value })}\n inputMode=\"decimal\"\n placeholder=\"0\"\n disabled={readOnly}\n />\n </label>\n </div>\n </>\n )}\n\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Plano de contas</span>\n <SearchSelect\n onSearch={localSearch(accountOptions)}\n value={(d.chartAccountId ?? defaultAccount) ?? undefined}\n displayValue={labelOf(accountOptions, d.chartAccountId ?? defaultAccount)}\n onChange={(id) => patch(item.id, { chartAccountId: id || null })}\n minChars={0}\n placeholder=\"Herda o padrão da nota\"\n noResultsLabel=\"Nenhum plano de contas\"\n searchingLabel=\"Buscando…\"\n disabled={readOnly}\n />\n </label>\n\n {item.stockMovementId && (\n <p className=\"text-[11px] text-success-soft-foreground\">\n <Check className=\"mr-1 inline h-3 w-3\" aria-hidden />\n Esta linha já deu entrada no estoque.\n </p>\n )}\n </div>\n </div>\n </Card>\n )\n })}\n </div>\n\n {/* ── 4. Dados de pagamento ──────────────────────────────────────── */}\n <Card className=\"p-4\">\n <div className=\"flex items-baseline justify-between\">\n <h3 className=\"text-sm font-semibold\">Dados de pagamento</h3>\n <p className=\"text-xs text-muted-foreground\">\n {instalments.length} {instalments.length === 1 ? 'parcela' : 'parcelas'} ·{' '}\n <span className=\"tabular-nums\">{money(instalmentSum)}</span>\n </p>\n </div>\n\n {note.declaredPayments.length > 0 && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n A nota declarou: {note.declaredPayments.map((p) => `${p.label ?? p.code} ${money(p.value)}`).join(' · ')}\n </p>\n )}\n\n <div className=\"mt-3 space-y-2\">\n {instalments.map((inst, i) => (\n <div key={i} className=\"grid items-end gap-2 sm:grid-cols-[2rem_1fr_1fr_1fr_2rem]\">\n <span className=\"pb-2 text-xs tabular-nums text-muted-foreground\">{inst.index}</span>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Vencimento</span>\n {/* Nota já aceita não tem vencimento editável, e um seletor de data\n apagado confunde mais que o texto: a parcela virou título. */}\n {readOnly ? (\n <p className=\"py-2 text-sm tabular-nums\">{day(inst.dueDate)}</p>\n ) : (\n <DatePicker\n value={inst.dueDate ?? ''}\n onChange={(v: string) =>\n setInstalments((prev) => prev.map((p, j) => (j === i ? { ...p, dueDate: v || null } : p)))}\n />\n )}\n </label>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Valor</span>\n <Input\n value={String(inst.amount)}\n inputMode=\"decimal\"\n disabled={readOnly}\n onChange={(e) =>\n setInstalments((prev) => prev.map((p, j) =>\n (j === i ? { ...p, amount: Number(e.target.value.replace(',', '.')) || 0 } : p)))}\n />\n </label>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Cód. barras / PIX</span>\n <Input\n value={inst.barcode ?? inst.pixKey ?? ''}\n disabled={readOnly}\n onChange={(e) =>\n setInstalments((prev) => prev.map((p, j) => (j === i ? { ...p, barcode: e.target.value } : p)))}\n />\n </label>\n {!readOnly && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Remover a parcela ${inst.index}`}\n onClick={() => setInstalments((prev) => prev.filter((_, j) => j !== i))}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n ))}\n </div>\n\n {!readOnly && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => setInstalments((prev) => [...prev, {\n index: prev.length + 1, number: null, dueDate: note.issueDate, amount: 0, paymentType: 'boleto',\n }])}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Adicionar parcela\n </Button>\n )}\n\n {/* O título nasce com a soma das parcelas. Se ela não bate com a nota, a\n tela diz — é a divergência que a financial/084 mediu em 6,3% dos casos. */}\n {Math.abs(instalmentSum - note.total) > 0.01 && (\n <Hint className=\"mt-3\">\n <span>\n <AlertTriangle className=\"mr-1 inline h-3.5 w-3.5\" aria-hidden />\n A nota diz {money(note.total)} e as parcelas somam {money(instalmentSum)}. O título vai\n nascer com <strong>{money(instalmentSum)}</strong> — é a soma das parcelas que define o\n saldo a pagar.\n </span>\n </Hint>\n )}\n </Card>\n\n {/* ── 5. Anexos da conta ─────────────────────────────────────────\n O quarto bloco do V1, e eu o tinha marcado como «adiado». Errado: a\n Laissa anexou 25 boletos no V1 e o último foi HOJE. A V2 já LÊ anexo\n (documents, subject_type='financial_invoice') e não tem escrita. */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Anexos da conta</h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Boleto, comprovante, foto da nota. No sistema antigo, anexar o boleto também{' '}\n <strong>preenchia as parcelas sozinho</strong> — é a automação mais útil e a mais invisível de lá.\n </p>\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <EmBreve\n label=\"Anexar boleto\"\n o_que=\"Guardar o arquivo no título que esta nota cria\"\n quantas=\"25 anexos no V1, o último hoje\"\n />\n <EmBreve\n label=\"Ler o código de barras do boleto\"\n o_que=\"Preencher vencimento e valor da parcela a partir do boleto anexado\"\n quantas=\"automação do V1 que ninguém documentou\"\n />\n </div>\n </Card>\n\n {error && (\n <Card className=\"border-destructive bg-destructive/5 p-4\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </Card>\n )}\n\n {/* ── Rodapé: Rejeitar / Salvar / Aceitar ──────────────────────────\n `pr-16` abre espaço para o FAB do assistente, que flutua no canto e\n cobria metade do «Aceitar» — o gesto mais importante desta tela. */}\n {!readOnly && (\n <div className=\"sticky bottom-0 -mx-4 flex items-center justify-between gap-3 border-t bg-card/95 px-4 py-3 pr-16 backdrop-blur\">\n <Button\n variant=\"ghost\"\n onClick={async () => { await rejectNote(note.id); onBack() }}\n disabled={saving || accepting}\n >\n <X className=\"mr-1.5 h-4 w-4\" />\n Rejeitar\n </Button>\n\n <div className=\"flex items-center gap-2\">\n {(missingType > 0 || missingProduct > 0) && (\n <p className=\"text-xs text-muted-foreground\">\n {missingType > 0 && `${missingType} sem tipo`}\n {missingType > 0 && missingProduct > 0 && ' · '}\n {missingProduct > 0 && `${missingProduct} sem produto`}\n </p>\n )}\n <Button variant=\"outline\" onClick={() => { void save() }} disabled={saving || accepting}>\n {saving && <Loader2 className=\"mr-1.5 h-4 w-4 animate-spin\" />}\n Salvar conciliação\n </Button>\n <Button\n onClick={() => { void accept() }}\n disabled={accepting || saving || missingType > 0 || missingProduct > 0}\n >\n {accepting ? <Loader2 className=\"mr-1.5 h-4 w-4 animate-spin\" /> : <Check className=\"mr-1.5 h-4 w-4\" />}\n Aceitar\n </Button>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction Field({ label, value, mono, small }: { label: string; value: string; mono?: boolean; small?: boolean }) {\n return (\n <div>\n <dt className={`text-muted-foreground ${small ? 'text-[10px]' : 'text-xs'}`}>{label}</dt>\n <dd className={`${mono ? 'tabular-nums' : ''} ${small ? 'text-xs' : 'text-sm'}`}>{value}</dd>\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// Manifesto de Notas — as NF-e que fornecedores emitiram CONTRA o CNPJ da casa.\n// ---------------------------------------------------------------------------\n// Manifestar ≠ dar entrada. É a distinção que organiza todo o fiscal:\n//\n// Manifesto responde à SEFAZ · obrigação com prazo · aceitar/recusar\n// Entrada de Notas responde ao estoque e ao financeiro · conciliar item a item\n//\n// Duas filas, com dois tamanhos: no V1 havia 118 pendentes de manifestação e 55\n// de conciliação.\n//\n// ── O que esta tela NÃO faz, por decisão do founder (30-09-2026) ───────────\n//\n// Aceitar/recusar de verdade fala com a PlugNotas, e o `dfe-plugnotas-sync`\n// continua rodando no V1 por um período. Então aqui a manifestação é LEGÍVEL,\n// não acionável: a tela mostra a fila e o estado que veio da SEFAZ, e o botão\n// leva para a conciliação, que é o que a V2 assume agora.\n//\n// Um botão «Aceitar» que não fala com a SEFAZ seria pior que a ausência dele —\n// o operador acharia que cumpriu o prazo.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { ExternalLink, FileText, ShieldCheck } from 'lucide-react'\nimport { Button, Card, Hint, Skeleton, ListFilterBar } from '@fayz-ai/ui'\nimport { EmBreve } from './ComingSoon'\nimport { listInboxNotes } from '../data/inbox'\nimport type { InboxNote } from '../types'\n\nconst money = (v: number) => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(v || 0)\nconst day = (iso: string | null) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\n/** O estado que a SEFAZ devolveu, na palavra que o V1 grava. */\nconst MANIFEST_TONE: Record<string, string> = {\n confirmada: 'bg-success-soft text-success-soft-foreground',\n processando: 'bg-info-soft text-info-soft-foreground',\n erro: 'bg-destructive/10 text-destructive',\n}\n\ntype Tab = 'pendentes' | 'confirmadas' | 'erro' | 'todas'\n\nexport interface ManifestViewProps {\n onOpenNote: (noteId: string) => void\n}\n\nexport function ManifestView({ onOpenNote }: ManifestViewProps) {\n const [notes, setNotes] = useState<InboxNote[]>([])\n const [loading, setLoading] = useState(true)\n const [tab, setTab] = useState<Tab>('pendentes')\n\n const reload = useCallback(async () => {\n setLoading(true)\n try {\n setNotes(await listInboxNotes({ filter: 'all', limit: 300 }))\n } finally {\n setLoading(false)\n }\n }, [])\n\n useEffect(() => { void reload() }, [reload])\n\n const shown = useMemo(() => notes.filter((n) => {\n const status = n.manifestationStatus ?? ''\n if (tab === 'todas') return true\n if (tab === 'confirmadas') return status === 'confirmada'\n if (tab === 'erro') return status === 'erro'\n return status !== 'confirmada'\n }), [notes, tab])\n\n const pending = notes.filter((n) => (n.manifestationStatus ?? '') !== 'confirmada').length\n\n const filters = useMemo(() => ([{\n id: 'manifestacao',\n label: 'Manifestação',\n allLabel: 'Todas',\n value: tab === 'todas' ? undefined : tab,\n onChange: (v: string | undefined) => setTab((v as Tab) ?? 'todas'),\n options: [\n { value: 'pendentes', label: 'Pendentes' },\n { value: 'confirmadas', label: 'Confirmadas' },\n { value: 'erro', label: 'Com erro' },\n ],\n }]), [tab])\n\n return (\n <div className=\"space-y-4\">\n <Card className=\"p-4\">\n <div className=\"flex items-start gap-3\">\n <ShieldCheck className=\"mt-0.5 h-5 w-5 text-muted-foreground\" aria-hidden />\n <div>\n <p className=\"text-sm font-medium\">\n {pending} {pending === 1 ? 'nota aguardando' : 'notas aguardando'} manifestação à SEFAZ\n </p>\n <p className=\"text-xs text-muted-foreground\">\n Manifestar responde à SEFAZ e tem prazo. Dar entrada responde ao seu estoque e ao\n financeiro — são duas filas.\n </p>\n </div>\n </div>\n <Hint className=\"mt-3\">\n <span>\n A manifestação continua sendo feita no sistema antigo por enquanto. Aqui você lê a fila e\n o que a SEFAZ respondeu; a entrada no estoque e a conta a pagar já são feitas nesta tela\n nova.\n </span>\n </Hint>\n\n {/* As ações do topo do V1. Ficam VISÍVEIS e desligadas: quem não vê o botão\n conclui que a V2 não faz, e volta para o V1 para conferir a fila. */}\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <EmBreve label=\"Aceitar / Recusar\" o_que=\"Responder à SEFAZ — é obrigação com prazo. Hoje a manifestação é feita no sistema antigo\" />\n <EmBreve label=\"Puxar por chave\" o_que=\"Buscar uma NF-e específica pela chave de acesso de 44 dígitos\" />\n <EmBreve label=\"Sincronizar agora\" o_que=\"Pedir à SEFAZ o que chegou desde a última varredura\" />\n <EmBreve label=\"Resincronizar tudo\" o_que=\"Refazer a varredura inteira do período\" />\n <EmBreve label=\"Diagnosticar\" o_que=\"Por que uma nota não chegou: certificado, credencial ou cursor parado\" />\n </div>\n </Card>\n\n <ListFilterBar filters={filters} onClear={() => setTab('todas')} activeCount={tab === 'todas' ? 0 : 1} />\n\n {loading ? (\n <div className=\"space-y-2\">{[0, 1, 2].map((i) => <Skeleton key={i} className=\"h-12 w-full\" />)}</div>\n ) : shown.length === 0 ? (\n <Card className=\"p-10 text-center\">\n <FileText className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Nenhuma nota nesta fila</p>\n </Card>\n ) : (\n <Card className=\"overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead className=\"border-b bg-muted/40 text-xs text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2 text-left font-medium\">Emissão</th>\n <th className=\"px-3 py-2 text-left font-medium\">Nº</th>\n <th className=\"px-3 py-2 text-left font-medium\">Fornecedor</th>\n <th className=\"px-3 py-2 text-right font-medium\">Valor</th>\n <th className=\"px-3 py-2 text-right font-medium\">Parcelas</th>\n <th className=\"px-3 py-2 text-center font-medium\">Manifestação</th>\n <th className=\"px-3 py-2 text-right font-medium\">Ações</th>\n </tr>\n </thead>\n <tbody>\n {shown.map((note) => (\n <tr key={note.id} className=\"border-b last:border-0 hover:bg-muted/30\">\n <td className=\"px-3 py-2 tabular-nums text-muted-foreground\">{day(note.issueDate)}</td>\n <td className=\"px-3 py-2 tabular-nums font-medium\">{note.number}</td>\n <td className=\"px-3 py-2\">{note.supplierName || '—'}</td>\n <td className=\"px-3 py-2 text-right tabular-nums\">{money(note.total)}</td>\n <td className=\"px-3 py-2 text-right tabular-nums text-muted-foreground\">\n {note.instalmentCount}\n </td>\n <td className=\"px-3 py-2 text-center\">\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${\n MANIFEST_TONE[note.manifestationStatus ?? ''] ?? 'bg-muted text-muted-foreground'\n }`}>\n {note.manifestationStatus ?? 'não manifestada'}\n </span>\n </td>\n <td className=\"px-3 py-2\">\n <div className=\"flex items-center justify-end gap-1.5\">\n {/* Os dois do V1 que dependem do arquivo ter subido: o XML e\n o DANFE moram em `documents`, e `document_id` da nota\n ainda está nulo — os bytes atravessam pelo estágio de\n assets, que não rodou. */}\n <EmBreve label=\"XML\" o_que=\"Ver o XML bruto autorizado desta nota\" />\n <EmBreve label=\"PDF\" o_que=\"Abrir o DANFE desta nota\" />\n <Button size=\"sm\" variant=\"outline\" onClick={() => onOpenNote(note.id)}>\n Abrir conciliação\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </Button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </Card>\n )}\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// A página de Entrada de Notas: lista, conciliação e manifesto numa moldura.\n// ---------------------------------------------------------------------------\n// As três vistas trocam por ESTADO LOCAL, não por rota. Trocar de rota remonta a\n// página e rebusca tudo — a lista pisca, a posição de rolagem se perde, e voltar\n// da conciliação recarrega 200 notas para mostrar a mesma coisa. O endereço\n// acompanha por `replaceState`, então recarregar a aba cai na vista certa e o\n// botão «voltar» do navegador não fica preso.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { InboundNotesView } from './InboundNotesView'\nimport { NoteReconcileView } from './NoteReconcileView'\nimport { ManifestView } from './ManifestView'\n\ntype View =\n | { kind: 'list' }\n | { kind: 'manifest' }\n | { kind: 'note'; id: string }\n\nconst HASH_PREFIX = '#/inbound-notes'\n\nfunction viewFromLocation(): View {\n if (typeof window === 'undefined') return { kind: 'list' }\n const hash = window.location.hash\n const note = hash.match(/\\/inbound-notes\\/note\\/([0-9a-f-]{36})/i)\n if (note) return { kind: 'note', id: note[1] }\n if (/\\/inbound-notes\\/manifest/.test(hash)) return { kind: 'manifest' }\n return { kind: 'list' }\n}\n\nconst pathOf = (view: View) =>\n view.kind === 'note' ? `${HASH_PREFIX}/note/${view.id}`\n : view.kind === 'manifest' ? `${HASH_PREFIX}/manifest`\n : HASH_PREFIX\n\nexport interface InboundNotesPageProps {\n /** Onde o título a pagar vive no app anfitrião. Sem isto o botão não aparece. */\n payableRoute?: (invoiceId: string) => string\n}\n\nexport function InboundNotesPage({ payableRoute }: InboundNotesPageProps = {}) {\n const [view, setView] = useState<View>(viewFromLocation)\n\n const go = useCallback((next: View) => {\n setView(next)\n if (typeof window !== 'undefined') {\n window.history.replaceState(null, '', pathOf(next))\n }\n }, [])\n\n // O «voltar» do navegador é um gesto legítimo aqui: quem entrou na conciliação\n // por um deep link espera sair dela com ele.\n useEffect(() => {\n if (typeof window === 'undefined') return\n const onPop = () => setView(viewFromLocation())\n window.addEventListener('popstate', onPop)\n window.addEventListener('hashchange', onPop)\n return () => {\n window.removeEventListener('popstate', onPop)\n window.removeEventListener('hashchange', onPop)\n }\n }, [])\n\n if (view.kind === 'note') {\n return (\n <NoteReconcileView\n noteId={view.id}\n onBack={() => go({ kind: 'list' })}\n onOpenInvoice={payableRoute\n ? (invoiceId) => { window.location.hash = payableRoute(invoiceId) }\n : undefined}\n />\n )\n }\n\n if (view.kind === 'manifest') {\n return (\n <div className=\"space-y-4\">\n <ManifestView onOpenNote={(id) => go({ kind: 'note', id })} />\n </div>\n )\n }\n\n return (\n <InboundNotesView\n onOpenNote={(id) => go({ kind: 'note', id })}\n onOpenManifest={() => go({ kind: 'manifest' })}\n />\n )\n}\n\n/**\n * O componente que o registro de rotas monta. Ele recebe as rotas sem prop, então\n * a configuração do host entra por fechamento — e a fábrica mora aqui, num `.tsx`,\n * para o manifesto continuar sendo TypeScript sem JSX.\n */\nexport function makeInboundNotesRoute(options: InboundNotesPageProps = {}): () => React.ReactElement {\n return function InboundNotesRoute() {\n return <InboundNotesPage {...options} />\n }\n}\n","import type { FinancialDataProvider } from '@fayz-ai/plugin-financial'\nimport type { PlugNotasFinancialProviderOptions } from '../types'\n\ntype FiscalDocument = NonNullable<Awaited<ReturnType<NonNullable<FinancialDataProvider['getNotaById']>>>>\n\nfunction fiscalReader(provider: FinancialDataProvider) {\n if (!provider.getNotaById) throw new Error('PlugNotas requires fiscal document reads from Financial.')\n return provider.getNotaById.bind(provider)\n}\n\nasync function committed(read: (id: string) => Promise<FiscalDocument | null>, id: string) {\n const document = await read(id)\n if (!document) throw new Error('Fiscal document was not found after the server operation.')\n return document\n}\n\nfunction resultError(result: { status: string; message?: string }, document: FiscalDocument, fallback: string) {\n if (result.status !== 'error') return\n throw new Error(result.message?.trim() || document.errorMessage?.trim() || fallback)\n}\n\nfunction cancellationPending(metadata: Record<string, unknown> | undefined): boolean {\n const provider = metadata?.plugnotas\n if (!provider || typeof provider !== 'object' || Array.isArray(provider)) return false\n return (provider as Record<string, unknown>).cancellationPending === true\n}\n\nfunction artifactUrl(value: unknown): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error('PlugNotas returned an invalid artifact URL.')\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n throw new Error('PlugNotas returned an invalid artifact URL.')\n }\n if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('PlugNotas returned an invalid artifact URL.')\n return parsed.toString()\n}\n\n/**\n * Decorates Financial without creating another fiscal ledger. The gateway only\n * requests server operations; every result returned to the UI is read back\n * from the server-committed `plg_financial_nfe` row.\n */\nexport function createPlugNotasFinancialProvider(\n options: PlugNotasFinancialProviderOptions,\n): FinancialDataProvider {\n const { base, gateway } = options\n\n const issueNota: NonNullable<FinancialDataProvider['issueNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.model !== 'nfce') throw new Error('PlugNotas currently authorizes NFC-e only.')\n if (!document.orderId?.trim()) throw new Error('PlugNotas NFC-e must be created from an order.')\n if (!['draft', 'error'].includes(document.status)) return document\n const result = await gateway.issue({ notaId: id, idempotencyKey: `nfce:${id}` })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not issue this NFC-e.')\n return saved\n }\n\n const refreshNota: NonNullable<FinancialDataProvider['refreshNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['processing', 'error'].includes(document.status) && !cancellationPending(document.metadata)) return document\n const result = await gateway.refresh({ notaId: id })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not refresh this NFC-e.')\n return saved\n }\n\n const cancelNota: NonNullable<FinancialDataProvider['cancelNota']> = async (id, reason) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.status !== 'issued') throw new Error('Only an issued NFC-e can be cancelled.')\n if (cancellationPending(document.metadata)) throw new Error('NFC-e cancellation is already in progress.')\n const normalized = reason?.trim() ?? ''\n if (normalized.length < 15 || normalized.length > 255) {\n throw new Error('Cancellation reason must contain between 15 and 255 characters.')\n }\n const result = await gateway.cancel({ notaId: id, reason: normalized })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not cancel this NFC-e.')\n return saved\n }\n\n const getNotaArtifactUrl: NonNullable<FinancialDataProvider['getNotaArtifactUrl']> = async (id, kind) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['issued', 'cancelled'].includes(document.status)) {\n throw new Error('Fiscal artifacts are available only after authorization.')\n }\n if (kind === 'cancellation_xml' && document.status !== 'cancelled') {\n throw new Error('Cancellation XML is available only after cancellation.')\n }\n return artifactUrl((await gateway.artifact({ notaId: id, kind })).url)\n }\n\n return new Proxy(base, {\n get(target, property, receiver) {\n if (property === 'issueNota') return issueNota\n if (property === 'refreshNota') return refreshNota\n if (property === 'cancelNota') return cancelNota\n if (property === 'getNotaArtifactUrl') return getNotaArtifactUrl\n return Reflect.get(target, property, receiver)\n },\n })\n}\n","// ---------------------------------------------------------------------------\n// As telas que ainda não existem, com o que se sabe sobre cada uma.\n// ---------------------------------------------------------------------------\n// Tudo aqui saiu de medição no V1 de produção da Artorius (tenant 12) entre\n// 29 e 30/09/2026 — o rastro de auditoria da LAISSA FLOR, que é quem lança. Os\n// números não são estimativa: são quantas vezes ela fez aquilo.\n// ---------------------------------------------------------------------------\nimport React from 'react'\nimport { ComingSoon } from './ComingSoon'\n\n/**\n * Grupos Fiscais — a 5ª tela do grupo no V1. Na V2 o grupo fiscal já existe como\n * CADASTRO (`fiscalRegistries`), só não tem porta aqui dentro.\n */\nexport function TaxGroupsView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Grupos Fiscais\"\n summary=\"Perfis tributários reutilizáveis — CFOP, CSOSN/CST, PIS, COFINS, ICMS — que os produtos usam na emissão.\"\n v1Path=\"Estoque → Notas Fiscais → Grupos Fiscais\"\n measured=\"Vazio no V1 da Artorius («Nenhum grupo fiscal cadastrado»), coerente com eles não emitirem nota. O Pertinho do Céu e o Espaço Facial têm 11 entre os dois.\"\n missing={[\n 'Trazer o cadastro para dentro do grupo: a tabela plg_fiscalbr_tax_groups já existe e já recebeu os 11 grupos do V1',\n 'Hoje ele só aparece na lista genérica de cadastros, longe de onde a nota é usada',\n 'Só faz sentido junto com Notas Emitidas — grupo fiscal é insumo de emissão',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n/** Notas Emitidas — no V1 FUNCIONA, e é o gap maior dos dois. */\nexport function IssuedNotesView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Notas Emitidas\"\n summary=\"As NF-e, NFS-e e NFC-e que a casa emitiu, com o estado de cada uma na SEFAZ — autorizada, processando, rejeitada ou cancelada — e a comanda ou fatura que deu origem a ela.\"\n v1Path=\"Estoque → Notas Fiscais → Notas Emitidas\"\n measured=\"A Artorius não emite nota hoje: em 80 documentos recebidos, zero emitidos. Quem emite é o Pertinho do Céu e o Espaço Facial.\"\n missing={[\n 'Ligar o emissor da PlugNotas a este CNPJ (o certificado A1 já está lá desde maio; falta a credencial chegar neste ambiente)',\n 'A lista com o estado na SEFAZ e o rastro de tentativas — as tabelas já existem (plg_fiscalbr_nfce_jobs, _events)',\n 'Abrir o XML autorizado e o DANFE de cada nota',\n 'Cancelar uma nota emitida, com justificativa',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n/** Notas Devolvidas — no V1 é STUB, e a tela diz isso. */\nexport function ReturnedNotesView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Notas Devolvidas\"\n summary=\"As notas fiscais de devolução: o que voltou para o fornecedor, e o que isso desfaz no estoque e na conta a pagar.\"\n v1Path=\"Estoque → Notas Fiscais → Notas Devolvidas\"\n v1AlsoMissing\n missing={[\n 'Decidir o gesto: devolver a nota INTEIRA ou só algumas linhas dela',\n 'A devolução ESTORNA o estoque que a entrada criou — e o movimento de estorno já existe no V2 (reverses_movement_id)',\n 'E abate o título a pagar, ou gera um crédito com o fornecedor. É decisão de produto, não de código',\n 'Emitir a NF-e de devolução exige emissor ligado — mesma dependência de Notas Emitidas',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n","// ---------------------------------------------------------------------------\n// O grupo «Notas Fiscais», pronto para o Estoque montar.\n// ---------------------------------------------------------------------------\n// O V1 agrupa CINCO telas sob «Notas Fiscais», dentro do Estoque:\n//\n// Manifesto de Notas funciona (118 pendentes lá)\n// Entrada de Notas funciona — é o grosso do trabalho\n// Grupos Fiscais funciona, vazio (é cadastro, e no V2 entra como registry)\n// Notas Emitidas funciona no V1, falta aqui\n// Notas Devolvidas STUB no V1 também\n//\n// Aqui vão as quatro que são TELA. O app chama isto em\n// `createInventoryPlugin({ extraViews: [inboundNotesInventoryView()] })`, e o\n// operador acha tudo onde sempre achou: dentro do Estoque.\n//\n// As que não funcionam não são escondidas. Quem não vê a função conclui que o V2\n// não a tem — e descobrimos isso pelo suporte, não pelo plano.\n// ---------------------------------------------------------------------------\nimport React from 'react'\nimport { InboundNotesPage, type InboundNotesPageProps } from './InboundNotesPage'\nimport { IssuedNotesView, ReturnedNotesView, TaxGroupsView } from './GapScreens'\n\nexport function inboundNotesInventoryView(options: InboundNotesPageProps = {}) {\n return {\n id: 'inbound-notes',\n label: 'Notas Fiscais',\n icon: 'FileText',\n render: () => <InboundNotesPage {...options} />,\n // A ordem é a do V1: Grupos Fiscais vem antes das duas de emissão, que é\n // onde ele é usado.\n //\n // Bonificação NÃO é aba. Ela chegou aqui por engano meu: no V1 não existe\n // esse menu — a bonificação é uma NATUREZA DE OPERAÇÃO que vem escrita na\n // nota (57 delas, em 11 grafias), e o que ela muda é o comportamento da\n // entrada: a mercadoria soma ao estoque e NÃO abre conta a pagar. O aviso\n // continua onde serve, na conciliação da nota. Uma tela vazia para um\n // comportamento é um menu que promete o que não vai entregar.\n children: [\n { id: 'tax-groups', label: 'Grupos Fiscais', render: () => <TaxGroupsView /> },\n { id: 'issued-notes', label: 'Notas Emitidas', render: () => <IssuedNotesView /> },\n { id: 'returned-notes', label: 'Notas Devolvidas', render: () => <ReturnedNotesView /> },\n ],\n }\n}\n","import { definePlugin, type PluginManifest } from '@fayz-ai/core'\nimport { createPlugNotasConnector, type CreatePlugNotasConnectorOptions } from './connectors/plugnotas'\nimport { MIGRATIONS } from './migrations'\nimport { fiscalRegistries } from './data/registries'\nimport { makeInboundNotesRoute } from './views/InboundNotesPage'\n\nexport * from './connectors/plugnotas'\nexport * from './lib/financial-provider'\nexport * from './types'\nexport * from './lib/nfe-xml'\nexport * from './data/inbox'\nexport { InboundNotesPage } from './views/InboundNotesPage'\nexport { InboundNotesView } from './views/InboundNotesView'\nexport { NoteReconcileView } from './views/NoteReconcileView'\nexport { ManifestView } from './views/ManifestView'\nexport { ComingSoon, EmBreve } from './views/ComingSoon'\nexport { IssuedNotesView, ReturnedNotesView, TaxGroupsView } from './views/GapScreens'\n/**\n * O grupo «Notas Fiscais» como o V1 o desenha: cinco telas sob uma aba. Duas\n * funcionam, três anunciam o que falta. O app passa isto para\n * `createInventoryPlugin({ extraViews })` e o Estoque desenha.\n */\nexport { inboundNotesInventoryView } from './views/inventoryView'\n\nexport interface CreatePlugNotasPluginOptions extends CreatePlugNotasConnectorOptions {\n /** Onde a linha de Entrada de Notas entra no rail. Default: `main`, posição 5 (depois do estoque). */\n navSection?: 'main' | 'secondary' | 'settings'\n navPosition?: number\n /**\n * Onde o título a pagar vive no app anfitrião, para o botão «Abrir a conta a\n * pagar» depois de aceitar. Sem isto o botão não aparece — um botão que leva a\n * lugar nenhum é pior que a ausência dele.\n */\n payableRoute?: (invoiceId: string) => string\n}\n\n/**\n * Fiscal Brasil is an addon: Financial owns the fiscal document, while this\n * package owns the provider connection and its asynchronous delivery trail.\n */\nexport function createPlugNotasPlugin(options: CreatePlugNotasPluginOptions = {}): PluginManifest {\n return definePlugin({\n id: 'fiscal-br',\n name: 'Fiscal Brasil',\n icon: 'ReceiptText',\n version: '0.1.0',\n apiVersion: 1,\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['financial'],\n // SEM linha no rail, de propósito.\n //\n // Entrada de Notas é assunto de ESTOQUE, não assunto do menu: no V1 o caminho\n // é `Estoque → Notas Fiscais → Entrada de Notas`. Montei como linha solta na\n // primeira tentativa e estava errado — quem vem do V1 procura dentro do\n // Estoque e não acha. O app entrega a tela ao inventário por\n // `createInventoryPlugin({ extraViews })`, e ela aparece como aba irmã de\n // Produtos, Movimentações e Contagens.\n //\n // A rota própria FICA: ela é o deep link (`#/inbound-notes`), e é por onde o\n // agente e um link de e-mail chegam sem passar pela faixa de abas.\n navigation: [],\n routes: [\n {\n path: '/inbound-notes',\n // O registro de rotas monta componentes sem prop. A opção do host entra\n // por fechamento, e a fábrica mora no `.tsx` para este manifesto seguir\n // sendo TypeScript sem JSX.\n component: makeInboundNotesRoute({ payableRoute: options.payableRoute }),\n permission: { feature: 'financial', action: 'read' as const },\n },\n ],\n // O grupo fiscal é CADASTRO, e por isso entra como registry e não como\n // rota própria: ele aparece onde os outros cadastros do produto aparecem.\n registries: fiscalRegistries,\n connectors: [createPlugNotasConnector(options)],\n functions: [{\n slug: 'plugnotas-bridge',\n ingress: 'none',\n verifyJwt: false,\n secrets: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n 'SUPABASE_URL',\n 'SUPABASE_ANON_KEY',\n 'SUPABASE_SERVICE_ROLE_KEY'\n ],\n grants: [\n 'plugnotas_register_emitter',\n 'plugnotas_disconnect_emitter',\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_prepare_nfce_cancel',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_get_artifact_locator',\n 'plugnotas_claim_nfce_recovery',\n 'plugnotas_record_nfce_attempt'\n ],\n }],\n migrations: MIGRATIONS.map((entry) => ({\n id: `fiscal-br-${entry.id}`,\n version: '1.0.0',\n sql: entry.sql,\n description: 'Durable PlugNotas delivery, recovery, webhook and emitter-registration boundary.',\n })),\n diagnostics: [{\n id: 'plugnotas-nfce-ready',\n description: 'NFC-e requires the shared connection, order, item and financial fiscal-document contracts.',\n requires: {\n tables: [\n 'connections',\n 'orders',\n 'items',\n 'plg_financial_nfe',\n 'plg_fiscalbr_nfce_jobs',\n 'plg_fiscalbr_nfce_events',\n 'plg_fiscalbr_webhook_receipts',\n ],\n rpcs: [\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_claim_nfce_recovery',\n ],\n env: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n ],\n },\n level: 'error',\n }],\n })\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/connectors/plugnotas.ts","../src/migrations/index.ts","../src/data/registries.ts","../src/lib/nfe-xml.ts","../src/data/inbox.ts","../src/views/InboundNotesView.tsx","../src/types.ts","../src/views/NoteReconcileView.tsx","../src/views/ManifestView.tsx","../src/views/InboundNotesPage.tsx","../src/lib/financial-provider.ts","../src/views/GapScreens.tsx","../src/views/inventoryView.tsx","../src/index.ts"],"names":["digits","money","day","useState","useCallback","useEffect","useMemo","jsxs","jsx","Card","Button","Trash2","Loader2","Hint","Skeleton"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA6jB/B,IAAM,0DAAA,GAA6D,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAqMnE,IAAM,+CAAA,GAAkD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA2WxD,IAAM,0CAAA,GAA6C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA;AAkPnD,IAAM,8CAAA,GAAiD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA;AAwBvD,IAAM,2CAAA,GAA8C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA+MpD,IAAM,yCAAA,GAA4C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAoBlD,IAAM,oDAAA,GAAuD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA;AAiC7D,IAAM,yDAAA,GAA4D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AA4NlE,IAAM,gEAAA,GAAmE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAsiBzE,IAAM,gEAAA,GAAmE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","file":"index.js","sourcesContent":["import type React from 'react'\nimport {\n connectionSettings,\n connectionStatus,\n createConnectionStore,\n settingsStatus,\n type ConnectionConfig,\n type ConnectorDefinition,\n type ConnectorField,\n type ConnectorSetting,\n} from '@fayz-ai/core'\nimport type { PlugNotasConnectorClient, PlugNotasEnvironment, PlugNotasSetupState } from '../types'\n\nexport const PLUGNOTAS_CONNECTOR_ID = 'plugnotas'\n\nconst PLUGNOTAS_MARK = \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230F766E'/%3E%3Cpath d='M10 7h12v18l-2-1.5-2 1.5-2-1.5-2 1.5-2-1.5-2 1.5V7Z' fill='white'/%3E%3Cpath d='M13 12h6M13 16h6M13 20h4' stroke='%230F766E' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E\"\n\nexport const PLUGNOTAS_FIELDS = [\n {\n key: 'emitterCnpj',\n label: 'CNPJ do emitente',\n type: 'text',\n placeholder: '00.000.000/0000-00',\n },\n] as const satisfies readonly ConnectorField[]\n\nexport const PLUGNOTAS_SETTINGS = [{\n key: 'environment',\n label: 'Ambiente fiscal',\n description: 'Sandbox simula o emissor. Homologação envia para a SEFAZ sem valor fiscal.',\n type: 'select',\n options: [\n { value: 'sandbox', label: 'Sandbox simulado' },\n { value: 'homologation', label: 'Homologação SEFAZ' },\n ],\n requiredToOperate: true,\n defaultValue: 'sandbox',\n}] as const satisfies readonly ConnectorSetting[]\n\nconst INTERNAL_SETTINGS = [\n 'certificateReady',\n 'cscReady',\n 'providerEmitterId',\n 'certificateExpiresAt',\n 'certificateFingerprint',\n // Non-secret operational data written by the host's server-side setup flow.\n // Declaring these keys keeps the shared connection store authoritative while\n // credentials (API key, A1 bytes/password, CSC) remain outside public JSON.\n 'stateRegistration',\n 'corporateName',\n 'tradeName',\n 'email',\n 'taxRegime',\n 'address',\n 'series',\n 'paymentMethod',\n]\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nfunction digits(value: string): string {\n return value.replace(/\\D/g, '')\n}\n\nexport function isValidCnpj(value: string): boolean {\n const normalized = digits(value)\n if (!/^\\d{14}$/.test(normalized) || /^(\\d)\\1{13}$/.test(normalized)) return false\n const digit = (base: string, weights: number[]) => {\n const sum = weights.reduce((total, weight, index) => total + Number(base[index]) * weight, 0)\n const remainder = sum % 11\n return remainder < 2 ? 0 : 11 - remainder\n }\n const first = digit(normalized.slice(0, 12), [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n const second = digit(`${normalized.slice(0, 12)}${first}`, [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n return normalized.endsWith(`${first}${second}`)\n}\n\nfunction environment(value: unknown): PlugNotasEnvironment {\n if (value === undefined || value === null || value === '' || value === 'sandbox') return 'sandbox'\n if (value === 'homologation') return value\n throw new Error('Produção não está disponível neste conector preview.')\n}\n\nfunction store() {\n return createConnectionStore(PLUGNOTAS_CONNECTOR_ID, {\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n settingsKeys: INTERNAL_SETTINGS,\n })\n}\n\nfunction deriveStatus(connection: ConnectionConfig | null) {\n if (!connection?.active) return { connected: false }\n const readiness = settingsStatus([...PLUGNOTAS_SETTINGS], connection)\n const certificateReady = connection.settings.certificateReady === true\n const cscReady = connection.settings.cscReady === true\n const expiry = typeof connection.settings.certificateExpiresAt === 'string'\n ? Date.parse(connection.settings.certificateExpiresAt)\n : Number.NaN\n const daysUntilExpiry = Number.isFinite(expiry) ? Math.ceil((expiry - Date.now()) / DAY_MS) : null\n const expired = daysUntilExpiry !== null && daysUntilExpiry <= 0\n const expiringSoon = daysUntilExpiry !== null && daysUntilExpiry > 0 && daysUntilExpiry <= 30\n const missingSettings = [...new Set([\n ...(readiness.missingSettings ?? []),\n ...(!certificateReady || expired ? ['certificate'] : []),\n ...(!cscReady ? ['csc'] : []),\n ])]\n\n return {\n connected: true,\n needsSetup: missingSettings.length > 0,\n ...(missingSettings.length ? { missingSettings } : {}),\n detail: expired\n ? 'Certificado A1 vencido'\n : !certificateReady\n ? 'Envie o certificado A1 do emitente.'\n : !cscReady\n ? 'Confirme o CSC e o ID Token do emitente.'\n : connection.settings.environment === 'homologation'\n ? 'Emitente pronto em homologação'\n : 'Emitente pronto no sandbox',\n ...(expiringSoon\n ? { issues: [`O certificado A1 vence em ${daysUntilExpiry} dia${daysUntilExpiry === 1 ? '' : 's'}.`] }\n : {}),\n plane: 'sync' as const,\n }\n}\n\nexport interface CreatePlugNotasConnectorOptions {\n client?: PlugNotasConnectorClient\n SetupPanel?: React.ComponentType\n}\n\nexport function createPlugNotasConnector(options: CreatePlugNotasConnectorOptions = {}): ConnectorDefinition {\n const connectionStore = store()\n return {\n id: PLUGNOTAS_CONNECTOR_ID,\n // PlugBank and PlugNotas are different products from the same vendor. The\n // directory key names the product, otherwise one silently replaces the\n // other in the generated connector map.\n catalogSlug: 'plugnotas',\n hostPluginId: 'financial',\n name: 'PlugNotas · NFC-e',\n description: 'Emita NFC-e pela TecnoSpeed sem expor certificado, senha ou API key no navegador.',\n icon: 'ReceiptText',\n logoUrl: PLUGNOTAS_MARK,\n authKind: 'api-key',\n category: 'erp',\n direction: 'outbound',\n planes: ['sync'],\n docsUrl: 'https://docs.plugnotas.com.br/',\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n permissions: [{\n kind: 'data',\n resource: 'fiscal-document',\n actions: ['read', 'write'],\n reason: 'Enviar a NFC-e e reconciliar situação, chave de acesso e artefatos no Financeiro.',\n sensitive: true,\n }],\n invokedAt: [{\n key: 'financial.nfce.issue',\n label: 'Quando um operador confirma a emissão da NFC-e de um pedido concluído',\n plane: 'sync',\n trigger: 'manual',\n touches: ['fiscal-document'],\n }],\n howItSyncs: [\n 'A emissão cria primeiro um comando durável e só depois chama o provedor.',\n 'Webhook e recuperação consultiva convergem o mesmo comando, sem reenviar no escuro.',\n ],\n ...connectionStatus(PLUGNOTAS_CONNECTOR_ID, deriveStatus, { store }),\n ...connectionSettings(connectionStore),\n async testConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) return { ok: false, message: 'Informe um CNPJ válido.' }\n let selected: PlugNotasEnvironment\n try {\n selected = environment(values.environment)\n } catch (error) {\n return { ok: false, message: error instanceof Error ? error.message : 'Ambiente inválido.' }\n }\n return options.client?.testEmitter\n ? options.client.testEmitter({ emitterCnpj, environment: selected })\n : { ok: true }\n },\n async saveConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await connectionStore.save({\n active: true,\n displayName: `Emitente ${emitterCnpj.slice(-6)}`,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(values.environment),\n certificateReady: false,\n cscReady: false,\n },\n })\n },\n ...(options.client?.disconnectEmitter\n ? { disconnect: () => options.client!.disconnectEmitter!() }\n : {}),\n disconnectNote: 'As notas existentes permanecem no Financeiro; somente novas emissões são interrompidas.',\n ExtraPanel: options.SetupPanel,\n }\n}\n\n/** Persist only server-confirmed readiness and non-secret certificate metadata. */\nexport async function markPlugNotasEmitterReady(input: PlugNotasSetupState): Promise<void> {\n const emitterCnpj = digits(input.emitterCnpj)\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await store().save({\n active: true,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(input.environment),\n certificateReady: input.certificateReady,\n cscReady: input.cscReady,\n providerEmitterId: input.providerEmitterId,\n certificateExpiresAt: input.certificateExpiresAt,\n certificateFingerprint: input.certificateFingerprint,\n },\n })\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_preserve_terminal_results_and_recover_leases.sql, 002_a_nota_que_chega_tem_onde_esperar.sql, 003_a_caixa_de_entrada_atravessa.sql, 004_o_grupo_fiscal_do_v1_repete_nome.sql, 005_a_nota_emitida_e_um_documento.sql, 006_o_grupo_fiscal_ganha_o_rail.sql, 007_a_rls_do_documento_passa_a_ser_legivel.sql, 008_a_nota_recebida_guarda_a_decisao_de_entrada.sql, 009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez.sql, 010_a_data_de_emissao_e_instante_e_a_competencia_e_dia.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- Fiscal Brasil / PlugNotas baseline.\n--\n-- This addon does not create a second fiscal ledger. \\`plg_financial_nfe\\`\n-- remains the authoritative document owned by plugin-financial. The tables\n-- below describe delivery to an external issuer: durable commands, attempts,\n-- webhooks and emitter ownership.\n--\n-- The file is additive and idempotent because the current restaurant pool is\n-- live. Applying it is deliberately outside this draft PR.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_jobs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Logical reference to plugin-financial's fiscal ledger. Cross-plugin\n -- physical foreign keys are intentionally forbidden: installation and\n -- removal of this addon must never rewrite another plugin's schema.\n nota_id uuid NOT NULL,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE RESTRICT,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE RESTRICT,\n operation text NOT NULL CHECK (operation IN ('issue', 'cancel')),\n status text NOT NULL DEFAULT 'queued'\n CHECK (status IN ('queued', 'running', 'waiting', 'succeeded', 'failed', 'manual_review')),\n idempotency_key text NOT NULL,\n provider_document_id text,\n integration_id text,\n request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb,\n provider_response jsonb NOT NULL DEFAULT '{}'::jsonb,\n attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),\n next_attempt_at timestamptz,\n locked_until timestamptz,\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_jobs_recovery_idx\n ON public.plg_fiscalbr_nfce_jobs (status, next_attempt_at, locked_until)\n WHERE status IN ('queued', 'waiting');\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_events (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n nota_id uuid NOT NULL,\n job_id uuid REFERENCES public.plg_fiscalbr_nfce_jobs(id) ON DELETE SET NULL,\n event_type text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_events_document_idx\n ON public.plg_fiscalbr_nfce_events (tenant_id, nota_id, created_at DESC);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_webhook_receipts (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n provider text NOT NULL DEFAULT 'plugnotas',\n provider_event_id text NOT NULL,\n tenant_id uuid REFERENCES public.tenants(id) ON DELETE SET NULL,\n nota_id uuid,\n payload_sha256 text NOT NULL,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n processing_error text,\n UNIQUE (provider, provider_event_id)\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_emitter_ownership (\n emitter_cnpj text PRIMARY KEY CHECK (emitter_cnpj ~ '^[0-9]{14}$'),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE CASCADE,\n environment text NOT NULL CHECK (environment IN ('sandbox', 'homologation')),\n provider_emitter_id text,\n certificate_expires_at timestamptz,\n certificate_fingerprint text,\n csc_ready boolean NOT NULL DEFAULT false,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, connection_id)\n);\n\nALTER TABLE public.plg_fiscalbr_nfce_jobs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_nfce_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_webhook_receipts ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_emitter_ownership ENABLE ROW LEVEL SECURITY;\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs;\nCREATE POLICY plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events;\nCREATE POLICY plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership;\nCREATE POLICY plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nREVOKE ALL ON public.plg_fiscalbr_nfce_jobs FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_nfce_events FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_webhook_receipts FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_emitter_ownership FROM anon, authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_jobs TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_events TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_emitter_ownership TO authenticated;\nGRANT ALL ON public.plg_fiscalbr_nfce_jobs TO service_role;\nGRANT ALL ON public.plg_fiscalbr_nfce_events TO service_role;\nGRANT ALL ON public.plg_fiscalbr_webhook_receipts TO service_role;\nGRANT ALL ON public.plg_fiscalbr_emitter_ownership TO service_role;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_register_emitter(\n p_tenant_id uuid,\n p_connection_id uuid,\n p_emitter_cnpj text,\n p_environment text,\n p_provider_emitter_id text DEFAULT NULL,\n p_certificate_expires_at timestamptz DEFAULT NULL,\n p_certificate_fingerprint text DEFAULT NULL,\n p_csc_ready boolean DEFAULT false\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_cnpj text := regexp_replace(coalesce(p_emitter_cnpj, ''), '[^0-9]', '', 'g');\nBEGIN\n IF v_cnpj !~ '^[0-9]{14}$' THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: invalid CNPJ' USING ERRCODE = '22023';\n END IF;\n IF p_environment NOT IN ('sandbox', 'homologation') THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: production is not enabled' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.connections c\n WHERE c.id = p_connection_id\n AND c.tenant_id = p_tenant_id\n AND c.connector_id = 'plugnotas'\n AND c.active\n ) THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: active connection not found' USING ERRCODE = 'P0002';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_emitter_ownership\n (emitter_cnpj, tenant_id, connection_id, environment, provider_emitter_id,\n certificate_expires_at, certificate_fingerprint, csc_ready, updated_at)\n VALUES\n (v_cnpj, p_tenant_id, p_connection_id, p_environment, p_provider_emitter_id,\n p_certificate_expires_at, p_certificate_fingerprint, p_csc_ready, now())\n ON CONFLICT (emitter_cnpj) DO UPDATE SET\n tenant_id = EXCLUDED.tenant_id,\n connection_id = EXCLUDED.connection_id,\n environment = EXCLUDED.environment,\n provider_emitter_id = EXCLUDED.provider_emitter_id,\n certificate_expires_at = EXCLUDED.certificate_expires_at,\n certificate_fingerprint = EXCLUDED.certificate_fingerprint,\n csc_ready = EXCLUDED.csc_ready,\n updated_at = now()\n WHERE public.plg_fiscalbr_emitter_ownership.tenant_id = EXCLUDED.tenant_id;\n\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: CNPJ belongs to another tenant' USING ERRCODE = '23505';\n END IF;\n\n UPDATE public.connections\n SET provider_account_key = v_cnpj,\n settings = settings || jsonb_build_object(\n 'environment', p_environment,\n 'certificateReady', p_certificate_expires_at IS NOT NULL,\n 'certificateExpiresAt', p_certificate_expires_at,\n 'certificateFingerprint', p_certificate_fingerprint,\n 'providerEmitterId', p_provider_emitter_id,\n 'cscReady', p_csc_ready\n ),\n status = CASE WHEN p_certificate_expires_at IS NOT NULL AND p_csc_ready THEN 'connected' ELSE 'pending' END,\n updated_at = now()\n WHERE id = p_connection_id AND tenant_id = p_tenant_id;\n\n RETURN jsonb_build_object('emitterCnpj', v_cnpj, 'environment', p_environment);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_disconnect_emitter(\n p_tenant_id uuid,\n p_connection_id uuid\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n DELETE FROM public.plg_fiscalbr_emitter_ownership\n WHERE tenant_id = p_tenant_id AND connection_id = p_connection_id;\n UPDATE public.connections\n SET active = false, status = 'revoked', settings = '{}'::jsonb,\n provider_state = '{}'::jsonb, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_connection_id AND connector_id = 'plugnotas';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_create_nfce_draft_for_order(\n p_tenant_id uuid,\n p_order_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_order public.orders%ROWTYPE;\n v_nota_id uuid;\nBEGIN\n -- Serialize draft creation per tenant/order without adding a column or\n -- index to the financial plugin's table. The order itself remains the\n -- stable idempotency boundary for one NFC-e draft.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || p_order_id::text, 0));\n\n SELECT * INTO v_order FROM public.orders\n WHERE tenant_id = p_tenant_id AND id = p_order_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_order.status NOT IN ('completed', 'paid', 'invoiced') THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order is not closed' USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.items i WHERE i.tenant_id = p_tenant_id AND i.order_id = p_order_id) THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order has no items' USING ERRCODE = '23514';\n END IF;\n\n SELECT n.id INTO v_nota_id FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.order_id = p_order_id AND n.model = 'nfce'\n ORDER BY n.created_at DESC LIMIT 1;\n IF v_nota_id IS NOT NULL THEN RETURN v_nota_id; END IF;\n\n INSERT INTO public.plg_financial_nfe\n (tenant_id, unit_id, model, status, order_id, contact_id, total_amount,\n emissor, metadata)\n VALUES\n (p_tenant_id, v_order.unit_id, 'nfce', 'draft', p_order_id, v_order.party_id,\n coalesce(v_order.total, 0), 'plugnotas',\n jsonb_build_object('source', 'order', 'orderKind', v_order.kind, 'orderChannel', v_order.channel))\n RETURNING id INTO v_nota_id;\n RETURN v_nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_idempotency_key text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_snapshot jsonb;\nBEGIN\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.model <> 'nfce' OR v_nota.order_id IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order-backed NFC-e not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_nota.status NOT IN ('draft', 'error', 'processing') THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: invalid document status %', v_nota.status USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_fiscalbr_emitter_ownership e\n WHERE e.tenant_id = p_tenant_id AND e.connection_id = p_connection_id\n AND e.csc_ready AND e.certificate_expires_at > now()\n ) THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: emitter is not ready' USING ERRCODE = '23514';\n END IF;\n\n SELECT jsonb_build_object(\n 'nota', to_jsonb(v_nota),\n 'order', to_jsonb(o),\n 'items', coalesce((\n SELECT jsonb_agg(to_jsonb(i) ORDER BY i.sort_order, i.id)\n FROM public.items i\n WHERE i.tenant_id = p_tenant_id AND i.order_id = v_nota.order_id\n ), '[]'::jsonb),\n -- Product tax metadata must be frozen in the same transaction as the order\n -- lines. Looking products up in the Edge Function would let a retry emit\n -- with NCM/CFOP changed after the operator confirmed the document.\n 'products', coalesce((\n SELECT jsonb_agg(to_jsonb(p) ORDER BY p.id)\n FROM public.products p\n WHERE p.tenant_id = p_tenant_id\n AND p.id IN (\n SELECT i.product_id FROM public.items i\n WHERE i.tenant_id = p_tenant_id\n AND i.order_id = v_nota.order_id\n AND i.product_id IS NOT NULL\n )\n ), '[]'::jsonb)\n ) INTO v_snapshot\n FROM public.orders o\n WHERE o.tenant_id = p_tenant_id AND o.id = v_nota.order_id;\n\n IF jsonb_array_length(v_snapshot->'items') = 0 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order has no items' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, request_snapshot, next_attempt_at, updated_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'issue', 'queued',\n p_idempotency_key, v_snapshot, now(), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE\n SET updated_at = now()\n RETURNING * INTO v_job;\n\n UPDATE public.plg_financial_nfe\n SET status = 'processing', error_message = NULL,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job.id, 'jobStatus', v_job.status, 'operation', 'issue'\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, p_nota_id, v_job.id, 'issue.queued', '{}'::jsonb);\n RETURN jsonb_build_object('jobId', v_job.id, 'snapshot', v_job.request_snapshot, 'replayed', v_job.attempts > 0);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce_cancel(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_reason text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job_id uuid;\n v_reason text := btrim(coalesce(p_reason, ''));\nBEGIN\n IF char_length(v_reason) NOT BETWEEN 15 AND 255 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: reason must contain 15 to 255 characters' USING ERRCODE = '22023';\n END IF;\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.status <> 'issued' OR v_nota.access_key IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: authorized NFC-e not found' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, provider_document_id, integration_id,\n request_snapshot, next_attempt_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'cancel', 'queued',\n 'nfce-cancel:' || p_nota_id::text,\n v_nota.metadata #>> '{plugnotas,providerDocumentId}',\n v_nota.metadata #>> '{plugnotas,integrationId}',\n jsonb_build_object('reason', v_reason), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE SET\n provider_document_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.provider_document_id,\n EXCLUDED.provider_document_id\n ),\n integration_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.integration_id,\n EXCLUDED.integration_id\n ),\n updated_at = now()\n RETURNING id INTO v_job_id;\n\n UPDATE public.plg_financial_nfe\n SET metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job_id, 'jobStatus', 'queued', 'operation', 'cancel', 'cancellationPending', true\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n RETURN jsonb_build_object('jobId', v_job_id, 'reason', v_reason);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status = 'processing' THEN 'issued'\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = CASE\n WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting'\n END,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN p_status = 'processing' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', CASE WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded' WHEN p_status = 'error' THEN 'failed' ELSE 'waiting' END,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND p_status = 'processing'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n IF v_receipt_id IS NULL THEN RETURN jsonb_build_object('duplicate', true); END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = now(), processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now()\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_get_artifact_locator(\n p_tenant_id uuid,\n p_nota_id uuid\n) RETURNS jsonb\nLANGUAGE sql SECURITY DEFINER SET search_path = '' STABLE AS $$\n SELECT jsonb_build_object(\n 'notaId', n.id,\n 'status', n.status,\n 'providerDocumentId', n.metadata #>> '{plugnotas,providerDocumentId}',\n 'integrationId', n.metadata #>> '{plugnotas,integrationId}'\n )\n FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.id = p_nota_id\n AND n.status IN ('issued', 'cancelled');\n$$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n\nREVOKE ALL ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) FROM PUBLIC, anon, authenticated;\n\nGRANT EXECUTE ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) TO service_role;\n`\n\nexport const MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES = `-- Incremental recovery fix. Preserve 000_baseline.sql and its recorded checksum.\n-- Only existing fiscal functions change; no parallel ledger/schema or backfill.\n-- CREATE OR REPLACE retains the service-role-only ACL from the baseline.\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = CASE WHEN p_status = 'running'\n THEN greatest(coalesce(locked_until, now()), now() + interval '2 minutes') ELSE NULL END,\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id AND status <> 'succeeded';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\n v_existing_status text;\n v_job_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n -- Match prepare/cancel's lock order: document, then job.\n SELECT status INTO v_existing_status FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: document not found' USING ERRCODE = 'P0002';\n END IF;\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n\n -- Late polling must not regress a concluded document or an active cancellation.\n IF v_existing_status = 'cancelled'\n OR (v_job.operation = 'issue' AND v_existing_status = 'issued' AND p_status <> 'cancelled')\n OR (v_job.status = 'succeeded' AND p_status IN ('processing', 'error')) THEN\n -- Old/interrupted jobs may still be running after the document concluded.\n -- Settle their lease too, otherwise recovery would claim them forever.\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = 'succeeded', locked_until = NULL, next_attempt_at = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n RETURN v_job.nota_id;\n END IF;\n\n v_job_status := CASE\n WHEN p_status = 'cancelled' OR (v_job.operation = 'issue' AND p_status = 'issued') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting' END;\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status <> 'cancelled' THEN v_existing_status\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = v_job_status,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN v_job_status = 'waiting' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN v_document_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', v_job_status,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND v_job_status = 'waiting'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\n v_receipt public.plg_fiscalbr_webhook_receipts%ROWTYPE;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n SELECT * INTO v_receipt FROM public.plg_fiscalbr_webhook_receipts\n WHERE provider = 'plugnotas' AND provider_event_id = p_provider_event_id FOR UPDATE;\n v_receipt_id := v_receipt.id;\n IF v_receipt.payload_sha256 IS DISTINCT FROM p_payload_sha256 THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_webhook: conflicting event payload' USING ERRCODE = '22023';\n END IF;\n IF v_receipt.processed_at IS NOT NULL AND v_receipt.processing_error IS NULL THEN\n RETURN jsonb_build_object('duplicate', true, 'matched', true);\n END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = NULL, processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now(), processing_error = NULL\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting', 'running')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n`\n\nexport const MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR = `-- A nota que chega tem onde esperar.\n--\n-- O V1 recebe NF-e de fornecedor pela SEFAZ e guarda cada uma numa caixa de\n-- entrada antes de alguém decidir o que fazer com ela: manifestar, importar\n-- para o estoque, ou nada. Essa caixa não tinha destino no V2.\n--\n-- dfe_inbox 703 a nota recebida, com o XML inteiro\n-- dfe_inbox_items 3.215 o item da nota, com todo o tributo\n-- dfe_inbox_payments 739 a forma de pagamento declarada\n-- dfe_inbox_duplicatas 830 o vencimento da duplicata\n-- fiscal_groups 11 o grupo fiscal (CFOP, CST, alíquotas)\n--\n-- Os números somam os dois tenants: Espaço Facial e Pertinho do Céu. É o único\n-- domínio fiscal que os dois usam.\n--\n-- ── O XML é arquivo, e arquivo mora em public.documents ─────────────────────\n--\n-- \\`dfe_inbox.xml_content\\` é o XML inteiro numa coluna de texto, e\n-- \\`pdf_storage_path\\` aponta para o DANFE no storage do V1. Os dois são ARQUIVO,\n-- e o V2 já tem o arquétipo: \\`public.documents\\`, com kind, checksum, storage_*\n-- e a RLS de arquivo que uma coluna de texto nunca teria.\n--\n-- Então a extensão guarda um PONTEIRO — \\`document_id\\` — e os bytes vão para o\n-- arquétipo, pelo estágio de assets (\\`make mig-assets\\`), que é quem alcança\n-- object storage. Enquanto os bytes não chegam, \\`document_id\\` fica nulo e o\n-- caminho de origem fica em metadata: a linha é verdadeira nos dois momentos.\n--\n-- ── O tributo vem inteiro, e de propósito ───────────────────────────────────\n--\n-- 30 colunas de imposto por item (ICMS, ICMS-ST, PIS, COFINS, IPI, com base,\n-- alíquota e valor de cada). É muita coluna, e a tentação é jogar tudo num\n-- jsonb. Não: isto é documento fiscal recebido, e a pergunta que se faz dele é\n-- \"quanto de ICMS entrou neste mês\" — uma soma, sobre coluna, com índice. Um\n-- jsonb transformaria toda apuração numa varredura.\n--\n-- O que VAI para jsonb é o \\`raw_xml_item\\`, que já é jsonb na origem e existe\n-- para conferência, não para conta.\n--\n-- Idempotente.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_documents (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n -- O ponteiro para o arquétipo. Nulo enquanto os bytes não subiram — o\n -- caminho de origem fica em metadata até lá.\n document_id uuid,\n access_key text,\n nfe_number text,\n nfe_series text,\n nfe_model text,\n issue_date timestamp with time zone,\n received_at timestamp with time zone,\n status text DEFAULT 'received'::text NOT NULL,\n -- A manifestação do destinatário é outro eixo que o status: uma nota pode\n -- estar recebida e não manifestada, e é a manifestação que a SEFAZ cobra.\n manifestation_status text,\n manifested_at timestamp with time zone,\n manifestation_attempts integer DEFAULT 0 NOT NULL,\n manifestation_response jsonb,\n supplier_party_id uuid,\n supplier_cnpj text,\n supplier_name text,\n supplier_ie text,\n total_value numeric(14,2),\n total_products numeric(14,2),\n total_discount numeric(14,2),\n total_freight numeric(14,2),\n total_insurance numeric(14,2),\n total_other numeric(14,2),\n total_icms_base numeric(14,2),\n total_icms_value numeric(14,2),\n total_icms_st_base numeric(14,2),\n total_icms_st_value numeric(14,2),\n total_pis_value numeric(14,2),\n total_cofins_value numeric(14,2),\n total_ipi_value numeric(14,2),\n nfe_protocol text,\n nfe_authorized_at timestamp with time zone,\n carrier_name text,\n carrier_cnpj text,\n freight_mode_code text,\n additional_info text,\n reviewed_at timestamp with time zone,\n -- O que essa nota virou no estoque, quando virou. Nulo é nota recebida e\n -- não importada, que é a maioria.\n inventory_operation_id uuid,\n owner_id uuid,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_documents IS\n 'A NF-e de fornecedor recebida da SEFAZ, esperando manifestação ou importação. V1: dfe_inbox.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_documents.document_id IS\n 'V1: xml_content + pdf_storage_path. O XML e o DANFE são arquivo; os bytes moram em public.documents e aqui fica o ponteiro.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_items (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n item_number integer,\n supplier_product_code text,\n ean_barcode text,\n ean_taxable text,\n description text,\n ncm text,\n cest text,\n cfop text,\n unit_commercial text,\n unit_taxable text,\n quantity_commercial numeric(18,4),\n quantity_taxable numeric(18,4),\n unit_price_commercial numeric(18,6),\n unit_price_taxable numeric(18,6),\n total_price numeric(14,2),\n discount numeric(14,2),\n freight numeric(14,2),\n insurance numeric(14,2),\n other_expenses numeric(14,2),\n icms_cst text, icms_csosn text, icms_origin text,\n icms_base numeric(14,2), icms_rate numeric(9,4), icms_value numeric(14,2),\n icms_st_base numeric(14,2), icms_st_value numeric(14,2),\n pis_cst text, pis_base numeric(14,2), pis_rate numeric(9,4), pis_value numeric(14,2),\n cofins_cst text, cofins_base numeric(14,2), cofins_rate numeric(9,4), cofins_value numeric(14,2),\n ipi_cst text, ipi_rate numeric(9,4), ipi_value numeric(14,2),\n -- O produto do V2 que esta linha da nota representa. \\`reconciled\\` é a\n -- decisão de quem conferiu; o id é o resultado dela.\n product_id uuid,\n reconciled boolean DEFAULT false NOT NULL,\n raw_xml_item jsonb,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_items IS\n 'O item da NF-e recebida, com o tributo em coluna — a apuração soma coluna, não varre jsonb. V1: dfe_inbox_items.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_payments (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n payment_index integer,\n payment_indicator text,\n payment_type_code text,\n payment_type_label text,\n value numeric(14,2),\n change_given numeric(14,2),\n card_brand text,\n card_acquirer_cnpj text,\n card_auth_code text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_duplicates (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n inbox_document_id uuid NOT NULL,\n duplicate_index integer,\n number text,\n due_date date,\n value numeric(14,2),\n -- O que essa duplicata virou no contas a pagar, se alguém a lançou.\n installment_id uuid,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_inbox_duplicates IS\n 'O vencimento declarado na NF-e recebida. Vira parcela do contas a pagar quando alguém lança a nota. V1: dfe_inbox_duplicatas.';\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_tax_groups (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n cfop text,\n csosn text,\n cst text,\n icms_origin text,\n icms_rate numeric(9,4),\n icms_bc_mode text,\n pis_situation text,\n pis_rate numeric(9,4),\n cofins_situation text,\n cofins_rate numeric(9,4),\n -- A reforma tributária já está no cadastro do V1 e vem junto: deixar de\n -- fora obrigaria a recadastrar tudo no dia em que IBS/CBS valerem.\n ibs_cbs_situation text,\n ibs_cbs_classification text,\n base_calculation_mode text,\n benefit_code text,\n cest text,\n poverty_fund_rate numeric(9,4),\n is_active boolean DEFAULT true NOT NULL,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_fiscalbr_tax_groups IS\n 'O grupo fiscal: CFOP, CST/CSOSN e alíquotas que o produto herda na emissão. V1: fiscal_groups. Traz IBS/CBS porque o cadastro do V1 já os tem.';\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- As chaves, os índices e a cerca\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = ('public.' || t)::regclass AND contype = 'p') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I PRIMARY KEY (id)', t, t || '_pkey');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_id_id_key') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I UNIQUE (tenant_id, id)', t, t || '_tenant_id_id_key');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_fkey') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE', t, t || '_tenant_fkey');\n END IF;\n END LOOP;\nEND $$;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n -- O arquivo pode ser apagado sem levar a nota junto: a nota fiscal existe\n -- mesmo sem o XML à mão, e é ela que a SEFAZ conhece.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_document_fkey\n FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_supplier_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_supplier_fkey\n FOREIGN KEY (supplier_party_id) REFERENCES public.people(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_operation_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_operation_fkey\n FOREIGN KEY (inventory_operation_id) REFERENCES public.plg_inventory_operations(id) ON DELETE SET NULL;\n END IF;\n\n -- Item, pagamento e duplicata não existem fora da nota: CASCADE.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_product_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_payments_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_payments ADD CONSTRAINT plg_fiscalbr_inbox_payments_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_document_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_document_fkey\n FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_installment_fkey') THEN\n ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_installment_fkey\n FOREIGN KEY (installment_id) REFERENCES public.plg_financial_invoice_installments(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\n-- A chave de acesso é única por casa: a mesma nota chegando duas vezes da SEFAZ\n-- é a mesma nota, e é isso que impede a importação em dobro.\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_access_key_uidx\n ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, access_key)\n WHERE access_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_pending_idx\n ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, unit_id, issue_date DESC)\n WHERE inventory_operation_id IS NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_document_idx\n ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, inbox_document_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_product_idx\n ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, product_id) WHERE product_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_payments_document_idx\n ON public.plg_fiscalbr_inbox_payments USING btree (tenant_id, inbox_document_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_duplicates_document_idx\n ON public.plg_fiscalbr_inbox_duplicates USING btree (tenant_id, inbox_document_id);\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_uidx\n ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));\n\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', t || '_updated_at', t);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()', t || '_updated_at', t);\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- Quem enxerga\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Nota fiscal é do FINANCEIRO, e a permissão é a que ele já usa. A caixa de\n-- entrada não tem unidade nos filhos — eles herdam a da nota —, então o escopo\n-- de unidade vale só no documento; o resto é do tenant, e é a CASCADE da FK que\n-- garante que ninguém veja filho de nota alheia.\n-- RLS, uma a uma e por extenso. O laço adiante já liga tudo isto — mas ele liga\n-- por \\`EXECUTE format(...)\\`, e o portão que revisa plugin lê o ARQUIVO, não o\n-- banco: para ele, tabela com tenant_id e sem um ENABLE literal é tabela\n-- aberta. Uma garantia que o revisor não consegue ler é uma garantia que\n-- ninguém confere.\nALTER TABLE public.plg_fiscalbr_inbox_documents ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_items ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_tax_groups ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_payments ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_inbox_duplicates ENABLE ROW LEVEL SECURITY;\n\nDO $$\nDECLARE\n t text;\n doc boolean;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',\n 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',\n 'plg_fiscalbr_tax_groups'] LOOP\n doc := t = 'plg_fiscalbr_inbox_documents';\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', t);\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.%I TO authenticated', t);\n EXECUTE format('GRANT ALL ON TABLE public.%I TO service_role', t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_select', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (%s)\n AND (SELECT app.has_permission('financial.read', %s)))$f$,\n t || '_authz_select', t,\n CASE WHEN doc THEN format('unit_id IS NULL OR (SELECT app.has_unit(%I.unit_id))', t) ELSE 'true' END,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_write', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', %s)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', %s)))$f$,\n t || '_authz_write', t,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END,\n CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n END LOOP;\nEND $$;\n\nINSERT INTO public.scoped_resources (resource_table, unit_column, owner_column, shareable, default_visibility, label)\nVALUES ('plg_fiscalbr_inbox_documents', 'unit_id', 'owner_id', false, 'unit', 'Notas recebidas')\nON CONFLICT (resource_table) DO UPDATE\n SET unit_column = EXCLUDED.unit_column, default_visibility = EXCLUDED.default_visibility, label = EXCLUDED.label;\n`\n\nexport const MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA = `-- A caixa de entrada atravessa.\n--\n-- A 002 fez as cinco tabelas. Esta escreve o de-para. As cinco usam o writer\n-- genérico \\`by_shape\\` (spine 123): as colunas do destino foram desenhadas\n-- olhando a origem, então o que falta é dizer qual nome vira qual — não uma\n-- função de upsert por tabela.\n--\n-- ── O arquivo não vem por aqui ──────────────────────────────────────────────\n--\n-- \\`xml_content\\` guarda o XML inteiro e \\`pdf_storage_path\\` aponta para o DANFE.\n-- Os dois saem do de-para com \\`-\\`: arquivo atravessa pelo estágio de assets,\n-- que é quem alcança object storage, e vira linha de \\`public.documents\\`. O\n-- caminho de origem fica em metadata para o estágio achar.\n--\n-- ── O fornecedor fica para a costura ────────────────────────────────────────\n--\n-- \\`supplier_party_id\\` não é preenchido aqui. A origem guarda CNPJ e nome, não\n-- um id de contato, e casar CNPJ com \\`public.people\\` é uma decisão de\n-- identidade — a mesma que já pôs 438 clientes em quarentena. Fica nulo, com o\n-- CNPJ na coluna ao lado, e uma passada de costura resolve quando alguém\n-- decidir a regra.\n--\n-- Idempotente.\n\nSET LOCAL migration.allowlist_unlock = 'on';\n\nSELECT migration._allow(\n 'fiscal_groups', 'public.plg_fiscalbr_tax_groups', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_tax_groups'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'name', 'name',\n 'cfop', 'cfop',\n 'csosn', 'csosn',\n 'cst', 'cst',\n 'icms_origin', 'icms_origin',\n 'icms_rate', 'icms_rate',\n 'icms_modalidade_bc', 'icms_bc_mode',\n 'pis_situation', 'pis_situation',\n 'pis_rate', 'pis_rate',\n 'cofins_situation', 'cofins_situation',\n 'cofins_rate', 'cofins_rate',\n 'ibs_cbs_situation', 'ibs_cbs_situation',\n 'ibs_cbs_classification', 'ibs_cbs_classification',\n 'base_calculation_mode', 'base_calculation_mode',\n 'cbenef', 'benefit_code',\n 'cest', 'cest',\n 'poverty_fund_rate', 'poverty_fund_rate',\n 'active', 'is_active',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O grupo fiscal: CFOP, CST/CSOSN e alíquotas que o produto herda na emissão. '\n 'IBS/CBS vêm junto porque o cadastro do V1 já os tem — deixar de fora '\n 'obrigaria a recadastrar tudo no dia em que a reforma valer.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox', 'public.plg_fiscalbr_inbox_documents', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_documents'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'company_id', 'unit_id@companies',\n 'access_key', 'access_key',\n 'nfe_number', 'nfe_number',\n 'nfe_series', 'nfe_series',\n 'nfe_model', 'nfe_model',\n 'issue_date', 'issue_date',\n 'received_at', 'received_at',\n 'status', 'status',\n 'manifestation_status', 'manifestation_status',\n 'manifested_at', 'manifested_at',\n 'manifestation_attempts', 'manifestation_attempts',\n 'manifestation_response', 'manifestation_response',\n 'supplier_cnpj', 'supplier_cnpj',\n 'supplier_name', 'supplier_name',\n 'supplier_ie', 'supplier_ie',\n 'total_value', 'total_value',\n 'total_products', 'total_products',\n 'total_discount', 'total_discount',\n 'total_freight', 'total_freight',\n 'total_insurance', 'total_insurance',\n 'total_other', 'total_other',\n 'total_icms_base', 'total_icms_base',\n 'total_icms_value', 'total_icms_value',\n 'total_icms_st_base', 'total_icms_st_base',\n 'total_icms_st_value', 'total_icms_st_value',\n 'total_pis_value', 'total_pis_value',\n 'total_cofins_value', 'total_cofins_value',\n 'total_ipi_value', 'total_ipi_value',\n 'nfe_protocol', 'nfe_protocol') ||\n -- \\`jsonb_build_object\\` aceita no máximo 100 argumentos, e este de-para tem\n -- 59 pares. Dois objetos concatenados, e não uma tabela a menos.\n jsonb_build_object(\n 'nfe_authorized_at', 'nfe_authorized_at',\n 'carrier_name', 'carrier_name',\n 'carrier_cnpj', 'carrier_cnpj',\n 'freight_mode_code', 'freight_mode_code',\n 'additional_info', 'additional_info',\n 'reviewed_at', 'reviewed_at',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'reviewed_by', '-',\n 'xml_content', '-',\n 'pdf_storage_path', 'jsonb:fiscalbr.v1_pdf_path',\n 'pdf_fetched_at', 'jsonb:fiscalbr.v1_pdf_fetched_at',\n 'danfe_import_id', 'jsonb:fiscalbr.v1_danfe_import_ref',\n 'plugnotas_payload', 'jsonb:fiscalbr.v1_plugnotas_payload',\n 'plugnotas_received_at', 'jsonb:fiscalbr.v1_plugnotas_received_at',\n 'nfe_cnf', 'jsonb:fiscalbr.nfe.cnf',\n 'nfe_natureza_operacao', 'jsonb:fiscalbr.nfe.natureza_operacao',\n 'nfe_finalidade', 'jsonb:fiscalbr.nfe.finalidade',\n 'nfe_tipo_operacao', 'jsonb:fiscalbr.nfe.tipo_operacao',\n 'nfe_destination', 'jsonb:fiscalbr.nfe.destination',\n 'supplier_address', 'jsonb:fiscalbr.supplier.street',\n 'supplier_number', 'jsonb:fiscalbr.supplier.number',\n 'supplier_complement', 'jsonb:fiscalbr.supplier.complement',\n 'supplier_neighborhood', 'jsonb:fiscalbr.supplier.neighborhood',\n 'supplier_city', 'jsonb:fiscalbr.supplier.city',\n 'supplier_state', 'jsonb:fiscalbr.supplier.state',\n 'supplier_postal_code', 'jsonb:fiscalbr.supplier.postal_code',\n 'supplier_phone', 'jsonb:fiscalbr.supplier.phone',\n 'supplier_email', 'jsonb:fiscalbr.supplier.email',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'A NF-e de fornecedor recebida da SEFAZ. \\`xml_content\\` sai com \\`-\\`: arquivo '\n 'atravessa pelo estágio de assets e vira public.documents, e o caminho do '\n 'DANFE fica em metadata para o estágio achar. O endereço do fornecedor vai '\n 'para metadata porque o fornecedor é \\`public.people\\`, e duplicá-lo em coluna '\n 'daria duas respostas para \"onde ele fica\".'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_items', 'public.plg_fiscalbr_inbox_items', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_items'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'item_number', 'item_number',\n 'product_code_supplier', 'supplier_product_code',\n 'ean_barcode', 'ean_barcode',\n 'ean_trib', 'ean_taxable',\n 'description', 'description',\n 'ncm', 'ncm',\n 'cest', 'cest',\n 'cfop', 'cfop',\n 'unit_commercial', 'unit_commercial',\n 'unit_taxable', 'unit_taxable',\n 'quantity_commercial', 'quantity_commercial',\n 'quantity_taxable', 'quantity_taxable',\n 'unit_price_commercial', 'unit_price_commercial',\n 'unit_price_taxable', 'unit_price_taxable',\n 'total_price', 'total_price',\n 'discount', 'discount',\n 'freight', 'freight',\n 'insurance', 'insurance',\n 'other_expenses', 'other_expenses',\n 'icms_cst', 'icms_cst',\n 'icms_csosn', 'icms_csosn',\n 'icms_origin', 'icms_origin',\n 'icms_base', 'icms_base',\n 'icms_rate', 'icms_rate',\n 'icms_value', 'icms_value',\n 'icms_st_base', 'icms_st_base',\n 'icms_st_value', 'icms_st_value',\n 'pis_cst', 'pis_cst',\n 'pis_base', 'pis_base',\n 'pis_rate', 'pis_rate',\n 'pis_value', 'pis_value',\n 'cofins_cst', 'cofins_cst',\n 'cofins_base', 'cofins_base',\n 'cofins_rate', 'cofins_rate',\n 'cofins_value', 'cofins_value',\n 'ipi_cst', 'ipi_cst',\n 'ipi_rate', 'ipi_rate',\n 'ipi_value', 'ipi_value',\n 'linked_product_id', 'product_id@products',\n 'reconciled', 'reconciled',\n 'raw_xml_item', 'raw_xml_item',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O item da nota, com o tributo em COLUNA — a apuração soma coluna, não varre '\n 'jsonb. \\`raw_xml_item\\` é a exceção: já é jsonb na origem e serve para '\n 'conferência, não para conta.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_payments', 'public.plg_fiscalbr_inbox_payments', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_payments'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'payment_index', 'payment_index',\n 'indicador_pagamento', 'payment_indicator',\n 'tipo_pagamento_code', 'payment_type_code',\n 'tipo_pagamento_label', 'payment_type_label',\n 'value', 'value',\n 'troco', 'change_given',\n 'card_flag', 'card_brand',\n 'card_acquirer_cnpj', 'card_acquirer_cnpj',\n 'card_auth_code', 'card_auth_code',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'A forma de pagamento declarada na nota recebida.'\n);\n\nSELECT migration._allow(\n 'dfe_inbox_duplicatas', 'public.plg_fiscalbr_inbox_duplicates', 'fiscal_br', 'by_shape',\n jsonb_build_object('target', 'public.plg_fiscalbr_inbox_duplicates'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',\n 'duplicata_index', 'duplicate_index',\n 'numero', 'number',\n 'vencimento', 'due_date',\n 'valor', 'value',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:fiscalbr.v1_ref'),\n 'O vencimento declarado na nota. Vira parcela do contas a pagar quando alguém '\n 'lança a nota — \\`installment_id\\` fica nulo até lá, porque a parcela é '\n 'decisão de quem lança, não da SEFAZ.'\n);\n\nDELETE FROM migration.excluded_tables\n WHERE source_table IN ('dfe_inbox', 'dfe_inbox_items', 'dfe_inbox_payments',\n 'dfe_inbox_duplicatas', 'fiscal_groups');\n\nRESET migration.allowlist_unlock;\n`\n\nexport const MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME = `-- O grupo fiscal do V1 repete nome.\n--\n-- A 002 criou índice ÚNICO em \\`(tenant_id, lower(name))\\`. O V1 tem, no tenant\n-- 8, \"Bebidas Alcoólicas\", \"Bebidas Não Alcoólicas\" e \"Vinhos e Espumantes\"\n-- DUAS vezes cada — grupos fiscais diferentes com o mesmo rótulo, e o V1\n-- permite. Três das onze linhas foram para a quarentena por uma regra que eu\n-- inventei, não que a origem tenha.\n--\n-- O índice vira comum: serve para buscar, não para proibir. Quem quiser proibir\n-- decide isso na tela, com o dado já dentro — e sabendo quais três são.\n--\n-- Esta correção nasceu dentro de \\`financial/083\\` e mudou de arquivo: o\n-- financeiro roda ANTES do fiscal_br na corrente, e um arquivo do financeiro\n-- que mexe numa tabela do fiscal_br falha do zero com\n-- \\`relation \"public.plg_fiscalbr_tax_groups\" does not exist\\`. Cada plugin mexe\n-- na tabela que é dele.\n--\n-- Idempotente.\n\nDROP INDEX IF EXISTS public.plg_fiscalbr_tax_groups_name_uidx;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_idx\n ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));\n`\n\nexport const MIGRATION_005_A_NOTA_EMITIDA_E_UM_DOCUMENTO = `-- A nota emitida é um DOCUMENTO, e o documento já tem arquétipo.\n--\n-- O V1 do Pertinho do Céu emitiu 496 notas (todas NFC-e: 440 concluídas, 51\n-- rejeitadas, 5 com erro) e nenhuma delas tem onde morar no V2. O que existe\n-- hoje aqui é a caixa de ENTRADA (\\`plg_fiscalbr_inbox_*\\`, a nota que chega do\n-- fornecedor) e o JOB de saída (\\`plg_fiscalbr_nfce_jobs\\`, a tentativa de\n-- emitir). Falta o resultado: a nota que a casa emitiu, com chave, protocolo e\n-- XML.\n--\n-- ── Por que pendurar em \\`public.documents\\` e não numa tabela solta ─────────\n--\n-- Porque a pergunta que o operador faz não é \"quais notas fiscais existem\",\n-- é \"o que foi emitido sobre ESTE pedido\". Hoje a resposta está espalhada:\n-- o anexo do título está em \\`documents\\`, o formulário está em \\`documents\\`, a\n-- foto do ponto está em \\`documents\\` — e a nota fiscal ficaria de fora, sendo\n-- o documento mais documento de todos.\n--\n-- \\`documents\\` é o arquétipo: \\`kind\\` diz a espécie, \\`subject_type\\`/\\`subject_id\\`\n-- dizem sobre o quê, e o plugin pendura o que só ele entende numa extensão 1:1\n-- pela chave — exatamente como \\`plg_forms_documents\\` já faz. Esta migração\n-- segue esse padrão, não inventa outro.\n--\n-- ── O que entra e o que NÃO entra ─────────────────────────────────────────\n--\n-- ENTRA o artefato legal e a trilha:\n-- xml_content 113 de 496 preenchidos, 618 kB no total (5,6 kB cada).\n-- É a prova da emissão e não se regenera. Fica.\n-- os quatro payloads 108 kB para as 496 notas inteiras. É a conversa com a\n-- SEFAZ, e é ela que explica as 51 rejeições.\n-- pdf_storage_path 84 de 496. Vira \\`documents.storage_path\\` com\n-- \\`storage_provider = 'v1-pending'\\`, a mesma convenção\n-- que \\`upsert_document\\` usa: o REGISTRO chegou, os bytes\n-- ainda não.\n--\n-- NÃO entra nada que o V2 já saiba responder por conta própria, e a emissão\n-- nova do V2 continua nascendo por \\`plg_fiscalbr_nfce_jobs\\` — este arquivo é o\n-- destino do resultado, não um segundo caminho de emissão.\n--\n-- ── Os dois ponteiros da nota do V1, que não são o mesmo ──────────────────\n--\n-- fiscal_documents.order_id 496 de 496 — a COMANDA (\\`table_orders\\`)\n-- fiscal_documents.invoice_id 118 de 496 — a VENDA (\\`invoices\\`)\n--\n-- Os dois chegam em \\`public.orders\\` no V2, e às vezes na MESMA linha (a\n-- comanda que virou nota adota a venda). Guardar os dois na mesma coluna\n-- perderia justamente a distinção: \\`order_id\\` na extensão é a comanda; a venda\n-- vai para \\`plg_fiscalbr_document_orders\\`, que é N:N porque uma nota pode\n-- juntar várias (511 vínculos para 496 notas).\n--\n-- Idempotente.\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. A espécie entra no vocabulário\n-- ═══════════════════════════════════════════════════════════════════════════\n-- \\`migration.upsert_document\\` RECUSA espécie que não esteja aqui, e faz certo:\n-- é o registro que impede \\`kind\\` de virar campo livre.\n\nINSERT INTO public.document_kinds (kind, plugin, description, statuses, status)\nVALUES ('fiscal_document', 'fiscal_br',\n 'A nota fiscal que a casa EMITIU (NFC-e, NF-e, NFS-e), com chave, protocolo e XML',\n ARRAY['draft','processing','authorized','rejected','error','cancelled','substituted'],\n 'declared')\nON CONFLICT (kind) DO UPDATE\n SET plugin = EXCLUDED.plugin,\n description = EXCLUDED.description,\n statuses = EXCLUDED.statuses,\n updated_at = now();\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. A extensão: o que só o fiscal entende\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_documents (\n -- A chave É o documento. Não há id próprio: a nota e o documento são a mesma\n -- coisa vista de dois lugares, e um segundo id só criaria a chance de eles\n -- discordarem.\n document_id uuid PRIMARY KEY REFERENCES public.documents(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n -- A comanda/pedido que originou a emissão.\n order_id uuid REFERENCES public.orders(id) ON DELETE SET NULL,\n model text NOT NULL,\n environment text,\n status text NOT NULL,\n series text,\n number text,\n -- 44 dígitos. Sem CHECK de formato: uma nota REJEITADA não tem chave, e uma\n -- chave que a SEFAZ devolveu torta é informação, não erro de digitação.\n access_key text,\n verification_code text,\n protocol text,\n provider text,\n provider_document_id text,\n provider_integration_id text,\n total_value numeric(14,2),\n iss_value numeric(14,2),\n recipient_snapshot jsonb,\n request_payload jsonb,\n response_payload jsonb,\n status_payload jsonb,\n rejection_payload jsonb,\n source_snapshot jsonb,\n -- O artefato legal. 5,6 kB por nota nas 113 que o têm; não se regenera.\n xml text,\n authorized_at timestamptz,\n last_polled_at timestamptz,\n emitted_by_user_id uuid,\n cancelled_at timestamptz,\n cancel_reason text,\n cancelled_by_user_id uuid,\n -- A cadeia de substituição. Auto-referência, então SET NULL: apagar a nota\n -- substituída não pode arrastar a que a substituiu.\n substitutes_document_id uuid REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE SET NULL,\n substituted_by_document_id uuid REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE SET NULL,\n observations text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nDO $$ BEGIN\n ALTER TABLE public.plg_fiscalbr_documents\n ADD CONSTRAINT plg_fiscalbr_documents_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\nEXCEPTION WHEN duplicate_object THEN NULL; END $$;\n\n-- A chave de acesso é única POR INQUILINO e só quando existe: 56 das 496 notas\n-- do Pertinho não têm chave nenhuma (rejeitadas e com erro), e um UNIQUE\n-- comum as empilharia todas num conflito só.\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_documents_chave_idx\n ON public.plg_fiscalbr_documents (tenant_id, access_key) WHERE access_key IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_documents_order_idx\n ON public.plg_fiscalbr_documents (tenant_id, order_id);\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_documents_status_idx\n ON public.plg_fiscalbr_documents (tenant_id, unit_id, status, authorized_at DESC);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. A trilha da emissão\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1.886 eventos para 496 notas — quase quatro por nota. É aqui que a rejeição\n-- diz o motivo, e é o único lugar em que ela diz.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_document_events (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n document_id uuid NOT NULL REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE CASCADE,\n event_type text NOT NULL,\n status text,\n justification text,\n request_payload jsonb,\n response_payload jsonb,\n created_by_user_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_document_events_doc_idx\n ON public.plg_fiscalbr_document_events (document_id, created_at DESC);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. Quais vendas a nota cobre\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_document_orders (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n document_id uuid NOT NULL REFERENCES public.plg_fiscalbr_documents(document_id) ON DELETE CASCADE,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE CASCADE,\n created_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (document_id, order_id)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_document_orders_order_idx\n ON public.plg_fiscalbr_document_orders (tenant_id, order_id);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. updated_at e a cerca\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$ BEGIN\n CREATE TRIGGER plg_fiscalbr_documents_updated_at BEFORE UPDATE\n ON public.plg_fiscalbr_documents FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\nEXCEPTION WHEN duplicate_object THEN NULL; END $$;\n\n-- \\`app.current_tenant_id()\\` e não \\`user_tenant_ids()\\`, pela razão que a 013 do\n-- plugin-tables teve de consertar em produção: a segunda devolve a UNIÃO das\n-- contas do chamador e mostraria a nota fiscal de um cliente para outro.\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_fiscalbr_documents','plg_fiscalbr_document_events',\n 'plg_fiscalbr_document_orders'] LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_select', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_insert', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_update', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_delete', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR SELECT USING (tenant_id = (select app.current_tenant_id()))', t || '_select', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR INSERT WITH CHECK (tenant_id = (select app.current_tenant_id()))', t || '_insert', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR UPDATE USING (tenant_id = (select app.current_tenant_id()))', t || '_update', t);\n EXECUTE format('CREATE POLICY %I ON public.%I FOR DELETE USING (tenant_id = (select app.current_tenant_id()))', t || '_delete', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_006_O_GRUPO_FISCAL_GANHA_O_RAIL = `-- O grupo fiscal ganha observação e etiqueta.\n--\n-- A tabela existe desde a 002 e nunca teve TELA: o grupo fiscal de toda conta\n-- migrada estava no banco sem porta. Estas duas colunas são o que falta para\n-- ele ter o mesmo rail de todo cadastro do produto — e a etiqueta tem uso\n-- imediato aqui, porque «Simples», «monofásico» e «substituição tributária»\n-- são recortes que nenhum campo do grupo responde e que decidem qual grupo\n-- alguém procura.\n--\n-- Idempotente.\n\nALTER TABLE public.plg_fiscalbr_tax_groups\n ADD COLUMN IF NOT EXISTS notes text,\n ADD COLUMN IF NOT EXISTS tags text[] DEFAULT '{}'::text[],\n ADD COLUMN IF NOT EXISTS unit_id uuid;\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_tags_gin\n ON public.plg_fiscalbr_tax_groups USING gin (tags);\n`\n\nexport const MIGRATION_007_A_RLS_DO_DOCUMENTO_PASSA_A_SER_LEGIVEL = `-- ---------------------------------------------------------------------------\n-- 007_a_rls_do_documento_passa_a_ser_legivel.sql\n--\n-- MESMO caso da 036 do plugin-tables, e a mesma medição antes de escrever.\n--\n-- \\`check-plugin-review\\` reprovou estas tabelas com *«cria public.X com\n-- tenant_id e nunca liga row security»*. Fui ao banco: **todas têm RLS ligada,\n-- com políticas** — medido no cluster do Pertinho em 29-09:\n--\n-- plg_fiscalbr_documents ........ rls=t, 4 políticas\n-- plg_fiscalbr_document_events .. rls=t, 4\n-- plg_fiscalbr_document_orders .. rls=t, 4\n--\n-- Não há vazamento. O \\`ENABLE\\` dessas tabelas mora dentro de um\n-- \\`DO $$ … EXECUTE format(...)\\`, e o portão lê o ARQUIVO, não o banco — uma\n-- garantia que o revisor não consegue ler é uma garantia que ninguém confere.\n--\n-- As migrations que as criam JÁ FORAM APLICADAS; reescrevê-las trocaria o\n-- checksum, que é a deriva de ledger pela qual este repositório para o mundo.\n-- Então a legibilidade entra por arquivo NOVO — o portão pergunta ao SQL\n-- INTEIRO do plugin.\n--\n-- Ligar RLS já ligada é no-op: isto não muda comportamento, torna conferível o\n-- que já era verdade.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nALTER TABLE public.plg_fiscalbr_documents ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_document_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_document_orders ENABLE ROW LEVEL SECURITY;\n`\n\nexport const MIGRATION_008_A_NOTA_RECEBIDA_GUARDA_A_DECISAO_DE_ENTRADA = `-- ---------------------------------------------------------------------------\n-- 008_a_nota_recebida_guarda_a_decisao_de_entrada.sql\n--\n-- A 002 trouxe a nota; esta guarda o que se DECIDE sobre ela.\n--\n-- O inbox do V2 já sabe tudo que o XML diz: fornecedor, item, NCM, CFOP, os 30\n-- campos de tributo. O que não tem onde morar é a decisão que o operador toma\n-- em cima da nota, e é ela que transforma documento em estoque e em dinheiro:\n--\n-- a qual PRODUTO esta linha corresponde (product_id, já existia)\n-- que TIPO de entrada ela é (entry_type)\n-- em que UNIDADE de estoque, com que FATOR (stock_unit_id, conversion_factor)\n-- em que PLANO DE CONTAS ela cai (chart_account_id)\n-- com que CUSTO o produto fica (cost_mode, unit_cost_new)\n--\n-- Sem essas colunas a tela de conciliação não tem onde salvar, e \"importar nota\n-- fiscal\" viraria um leitor de XML — que é exatamente o que o V2 tinha.\n--\n-- ── O vocabulário vem do V1 medido, não de um enum inventado ────────────────\n--\n-- \\`danfe_import_items.entry_type\\` no V1 de produção (29-09-2026), 3.402 linhas:\n--\n-- insumo 2.303 revenda 546 patrimonio 280\n-- despesa 262 servico 11 (null) 5\n--\n-- São cinco, e duas delas — \\`despesa\\` e \\`servico\\` — NÃO viram estoque. É por\n-- isso que o tipo é coluna da linha e não da nota: a mesma NF-e traz o insumo\n-- que entra no estoque e a taxa de entrega que só vira despesa.\n--\n-- \\`cost_mode\\` tem UM valor em 3.407 linhas: \\`novo\\`. A média ponderada existe na\n-- tela do V1 e ninguém nunca escolheu. Fica no CHECK por paridade — tirar a\n-- opção é decisão de produto, e o dado não autoriza ninguém a tomá-la por aqui.\n--\n-- ── Por que \\`stock_movement_id\\` na linha, e não só na nota ──────────────────\n--\n-- Uma nota pode virar estoque PARCIALMENTE: o V1 tem os status \\`partial\\` e\n-- \\`partial_stocked\\` justamente porque o operador concilia 1 de 6 itens hoje e o\n-- resto amanhã. Guardar o movimento só no cabeçalho responderia \"esta nota\n-- entrou?\" e nunca \"esta LINHA entrou?\" — e é a segunda pergunta que decide se\n-- aceitar de novo duplica saldo.\n--\n-- ── O de-para é o que faz a segunda nota ser rápida ─────────────────────────\n--\n-- \\`supplier_product_mappings\\` no V1: (CNPJ do fornecedor, código do produto no\n-- fornecedor) → produto, tipo, plano, unidade, fator. 66 linhas na Artorius, e é\n-- o que faz a nota seguinte do mesmo fornecedor chegar já vinculada. Sem ele,\n-- toda importação recomeça do zero e o ganho de importar XML desaparece.\n--\n-- A chave é (tenant, CNPJ, código) e NÃO inclui unidade: o de-para é\n-- conhecimento sobre o catálogo do fornecedor, não sobre uma loja.\n--\n-- Aditivo e idempotente. Nada aqui apaga, renomeia ou reescreve dado existente.\n-- ---------------------------------------------------------------------------\n\n-- ── A decisão, linha a linha ────────────────────────────────────────────────\n\nALTER TABLE public.plg_fiscalbr_inbox_items\n ADD COLUMN IF NOT EXISTS entry_type text,\n ADD COLUMN IF NOT EXISTS chart_account_id uuid,\n ADD COLUMN IF NOT EXISTS stock_unit_id uuid,\n -- A quantidade que entra no estoque, já convertida. Derivada\n -- (quantity_commercial × conversion_factor), mas GRAVADA: é o número que o\n -- operador viu na tela antes de aceitar, e recalcular depois com um fator que\n -- alguém editou daria outra resposta para a mesma entrada.\n ADD COLUMN IF NOT EXISTS stock_quantity numeric(18,4),\n ADD COLUMN IF NOT EXISTS conversion_factor numeric(14,4) NOT NULL DEFAULT 1,\n ADD COLUMN IF NOT EXISTS cost_mode text,\n ADD COLUMN IF NOT EXISTS unit_cost_new numeric(18,6),\n -- O movimento que ESTA linha produziu. Nulo = não entrou.\n ADD COLUMN IF NOT EXISTS stock_movement_id uuid,\n -- Divergência: chegou menos do que a nota diz. O V1 guarda quantidade, motivo\n -- e observação, e a nota continua válida — quem responde pela diferença é o\n -- fornecedor, não o estoque.\n ADD COLUMN IF NOT EXISTS shortage_quantity numeric(18,4),\n ADD COLUMN IF NOT EXISTS shortage_reason text,\n ADD COLUMN IF NOT EXISTS shortage_note text;\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_entry_type_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_entry_type_chk\n CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','despesa','servico'));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_cost_mode_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_cost_mode_chk\n CHECK (cost_mode IS NULL OR cost_mode IN ('novo','media'));\n END IF;\n -- Um fator zero ou negativo não converte nada: transformaria a quantidade da\n -- nota em zero estoque sem ninguém acusar. É o defeito silencioso que o\n -- FLOW.md do V1 nomeia («fator de conversão errado é silencioso»), e aqui ele\n -- deixa de ser possível.\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_factor_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_items\n ADD CONSTRAINT plg_fiscalbr_inbox_items_factor_chk CHECK (conversion_factor > 0);\n END IF;\nEND $$;\n\n-- FK lógica para o plano de contas e a unidade: as duas são de OUTROS plugins\n-- (financial e inventory), e a 000 deste plugin já estabelece que FK física\n-- entre plugins é proibida — instalar ou remover um addon não reescreve o\n-- schema do vizinho. A integridade é verificada na RPC, que é quem escreve.\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.chart_account_id IS\n 'Logical reference to plg_financial_chart_of_accounts.id — validated by the accept RPC, not by a cross-plugin FK.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.stock_unit_id IS\n 'Logical reference to plg_inventory_measurement_units.id — validated by the accept RPC.';\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_items.stock_quantity IS\n 'quantity_commercial x conversion_factor, stored as shown on screen before accepting.';\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_pending_idx\n ON public.plg_fiscalbr_inbox_items (tenant_id, inbox_document_id)\n WHERE reconciled IS NOT TRUE;\n\n-- ── A decisão no cabeçalho da nota ──────────────────────────────────────────\n\nALTER TABLE public.plg_fiscalbr_inbox_documents\n -- «itens sem plano herdarão este» — o plano da nota é padrão com HERANÇA, não\n -- obrigação por item. A frase é do V1 e a coluna existe para ela.\n ADD COLUMN IF NOT EXISTS default_chart_account_id uuid,\n -- O título a pagar que esta nota gerou. Mesma ideia do inventory_operation_id\n -- que a 002 já trouxe para o estoque: a nota aponta para as duas travessias.\n ADD COLUMN IF NOT EXISTS invoice_id uuid,\n ADD COLUMN IF NOT EXISTS stocked_at timestamptz,\n -- A natureza da operação declarada na NF-e («REM BONIFICACAO NAO\n -- CONTRIBUINTE»). O bloco de situação fiscal da conciliação mostra isso, e\n -- sem a coluna a tela mostraria um campo vazio.\n ADD COLUMN IF NOT EXISTS nature_operation text,\n ADD COLUMN IF NOT EXISTS default_location_id uuid;\n\nCOMMENT ON COLUMN public.plg_fiscalbr_inbox_documents.invoice_id IS\n 'Logical reference to plg_financial_invoices.id created by fiscalbr_accept_inbox_document.';\n\n-- ── A parcela sabe como se paga ─────────────────────────────────────────────\n--\n-- A duplicata do XML traz número, vencimento e valor. O que o operador acrescenta\n-- na tela é COMO ela se paga — e o boleto que ele anexa carrega o código de\n-- barras, que é o que a automação do V1 lê para preencher a parcela.\n\nALTER TABLE public.plg_fiscalbr_inbox_duplicates\n ADD COLUMN IF NOT EXISTS payment_type text,\n ADD COLUMN IF NOT EXISTS barcode text,\n ADD COLUMN IF NOT EXISTS pix_key text,\n ADD COLUMN IF NOT EXISTS payment_method_id uuid;\n\n-- O vocabulário é o do V1, medido em \\`danfe_payments.payment_type\\` (1.069 linhas):\n-- boleto 660 · sem_pagamento 108 · outro 107 · dinheiro 65 ·\n-- duplicata_mercantil 45 · pix 35 · cartao_credito 35 · cartao_debito 9 ·\n-- credito_loja 4 · vale_presente 1\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_payment_type_chk') THEN\n ALTER TABLE public.plg_fiscalbr_inbox_duplicates\n ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_payment_type_chk\n CHECK (payment_type IS NULL OR payment_type IN (\n 'boleto','pix','dinheiro','cartao_credito','cartao_debito',\n 'duplicata_mercantil','credito_loja','vale_presente','sem_pagamento','outro'));\n END IF;\nEND $$;\n\n-- ── O de-para fornecedor × produto ──────────────────────────────────────────\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_supplier_product_map (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Só dígitos, normalizado na escrita: o XML traz o CNPJ cru e a tela do V1\n -- aceitava pontuação, então duas grafias do mesmo fornecedor viravam dois\n -- de-para e a segunda nota não achava o primeiro.\n supplier_cnpj text NOT NULL,\n supplier_product_code text NOT NULL,\n product_id uuid NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,\n entry_type text,\n chart_account_id uuid,\n stock_unit_id uuid,\n conversion_factor numeric(14,4) NOT NULL DEFAULT 1,\n cost_mode text,\n -- Quantas vezes este de-para acertou. Serve para a tela mostrar de onde veio o\n -- vínculo («já usado 12 vezes») em vez de um produto que apareceu sozinho.\n hit_count integer NOT NULL DEFAULT 0,\n last_used_at timestamptz,\n owner_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_fiscalbr_supplier_product_map_factor_chk CHECK (conversion_factor > 0),\n CONSTRAINT plg_fiscalbr_supplier_product_map_entry_type_chk\n CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','despesa','servico')),\n CONSTRAINT plg_fiscalbr_supplier_product_map_cost_mode_chk\n CHECK (cost_mode IS NULL OR cost_mode IN ('novo','media'))\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_supplier_product_map_uq\n ON public.plg_fiscalbr_supplier_product_map (tenant_id, supplier_cnpj, supplier_product_code);\n\nALTER TABLE public.plg_fiscalbr_supplier_product_map ENABLE ROW LEVEL SECURITY;\n\n-- Mesmas políticas das tabelas do inbox (002): o de-para é conhecimento do\n-- financeiro sobre o fornecedor, então lê com \\`financial.read\\` e escreve com\n-- \\`financial.edit\\`. Não tem unit_id — é catálogo do fornecedor, não da loja.\nDROP POLICY IF EXISTS plg_fiscalbr_supplier_product_map_authz_select ON public.plg_fiscalbr_supplier_product_map;\nCREATE POLICY plg_fiscalbr_supplier_product_map_authz_select\n ON public.plg_fiscalbr_supplier_product_map FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL::uuid)));\n\nDROP POLICY IF EXISTS plg_fiscalbr_supplier_product_map_authz_write ON public.plg_fiscalbr_supplier_product_map;\nCREATE POLICY plg_fiscalbr_supplier_product_map_authz_write\n ON public.plg_fiscalbr_supplier_product_map FOR ALL TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', NULL::uuid)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.edit', NULL::uuid)));\n\nCOMMENT ON TABLE public.plg_fiscalbr_supplier_product_map IS\n 'Supplier catalogue memory: (CNPJ, supplier product code) -> the entry decision, so the next note from the same supplier arrives already bound. Mirrors V1 supplier_product_mappings.';\n`\n\nexport const MIGRATION_009_ACEITAR_A_NOTA_ESCREVE_ESTOQUE_E_TITULO_DE_UMA_VEZ = `-- ---------------------------------------------------------------------------\n-- 009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez.sql\n--\n-- É o arquivo que fecha o porte: «Aceitar» na conciliação dá entrada no estoque\n-- E cria a conta a pagar, numa transação só.\n--\n-- Medido no V1 de produção (tenant 12 da Artorius, 29-09-2026): **72 de 72**\n-- movimentos de estoque nasceram com \\`danfe_import_item_id\\`. Nenhum foi digitado.\n-- Dar ao V2 uma tela de movimentação manual e chamar isso de paridade seria\n-- entregar a tela que eles nunca abriram.\n--\n-- ── Não reimplementa estoque nem título. CHAMA quem já faz ──────────────────\n--\n-- O V2 já tem as duas primitivas, e as duas já são idempotentes:\n--\n-- public.inventory_receive(location, lines, document, idempotency_key)\n-- public.financial_create_invoice(direction, total, counterparty, …, key)\n--\n-- Reescrever INSERT em \\`plg_inventory_stock_movements\\` aqui daria uma segunda\n-- resposta para «como entra estoque» — e a posição é derivada por gatilho, então\n-- a segunda resposta sairia com saldo certo e sem ninguém acusar. A entrada de\n-- nota é mais um CHAMADOR dessas portas, como a requisição e a contagem.\n--\n-- Idempotência vem de graça daí: a chave é derivada da chave de acesso da NF-e,\n-- que é única por documento fiscal no Brasil. Aceitar duas vezes devolve o mesmo\n-- resultado sem escrever de novo — o AC7 do plano.\n--\n-- ── O total do título é a soma das PARCELAS ────────────────────────────────\n--\n-- Regra herdada da \\`plugin-financial/084\\`, que mediu: em 6,3% das notas a soma\n-- das duplicatas não bate com o total da nota. \\`plg_financial_invoices\\` é\n-- imutável depois de emitido, então um título aberto com o total errado fica\n-- com saldo errado para sempre em toda tela que faz «total − pago».\n-- O total da nota continua legível no \\`metadata\\` e na caixa de entrada.\n--\n-- E a MESMA chave de idempotência da 084 (\\`danfe:<chave>\\`): uma nota que o porte\n-- histórico já transformou em título não pode ganhar um segundo aqui.\n--\n-- ── Despesa e serviço não viram estoque ────────────────────────────────────\n--\n-- \\`entry_type\\` decide por LINHA. A mesma NF-e traz o insumo que entra no estoque\n-- e a taxa de entrega que só vira despesa — e as duas precisam ir para o mesmo\n-- título a pagar. Por isso a lista de linhas do estoque é um FILTRO sobre os\n-- itens, não os itens.\n--\n-- Idempotente. Só cria função.\n-- ---------------------------------------------------------------------------\n\n-- ── Ajudantes ──────────────────────────────────────────────────────────────\n\n-- O XML traz o CNPJ cru e a tela aceita pontuação. Duas grafias do mesmo\n-- fornecedor viravam dois de-para no V1, e a segunda nota não achava o primeiro.\nCREATE OR REPLACE FUNCTION public.plg_fiscalbr_digits(p_value text)\nRETURNS text LANGUAGE sql IMMUTABLE SET search_path TO '' AS $$\n SELECT regexp_replace(coalesce(p_value, ''), '[^0-9]', '', 'g')\n$$;\n\n-- ── Receber a nota: o XML já lido vira linhas ──────────────────────────────\n--\n-- O XML é decomposto no NAVEGADOR e chega aqui como jsonb. Parsear NF-e em\n-- PL/pgSQL seria escrever um leitor de XML dentro do banco, sem teste unitário\n-- possível e sem a mensagem de erro que a tela precisa dar para um arquivo que\n-- não é uma nota.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_stage_inbox_document(p_note jsonb)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_key text := btrim(coalesce(p_note->>'access_key', ''));\n v_cnpj text := public.plg_fiscalbr_digits(p_note->'supplier'->>'cnpj');\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_unit uuid := nullif(p_note->>'unit_id', '')::uuid;\n v_party uuid;\n v_item jsonb;\n v_map public.plg_fiscalbr_supplier_product_map%ROWTYPE;\n v_n integer := 0;\n v_matched integer := 0;\nBEGIN\n PERFORM public.plg_financial_require_permission('financial.create', v_unit);\n\n IF length(v_key) <> 44 THEN\n RAISE EXCEPTION 'fiscalbr: chave de acesso inválida (esperado 44 dígitos, veio %)', length(v_key)\n USING ERRCODE = '22023';\n END IF;\n\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND access_key = v_key;\n\n -- Nota já aceita não é reimportada: o XML é o mesmo documento fiscal, e\n -- reescrever os itens apagaria a decisão que virou estoque e título.\n IF FOUND AND (v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL) THEN\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'access_key', v_key, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'items', 0, 'matched', 0);\n END IF;\n\n -- O fornecedor é uma PESSOA, não um nome. A 094 do financial documenta o custo\n -- de não ter o ponteiro: praticamente todo título nascido de DANFE ficou sem\n -- contraparte. Casar por CNPJ acerta; casar por nome acertaria 137 de 554.\n IF v_cnpj <> '' THEN\n SELECT id INTO v_party FROM public.people\n WHERE tenant_id = v_tenant AND public.plg_fiscalbr_digits(document_number) = v_cnpj\n LIMIT 1;\n END IF;\n\n INSERT INTO public.plg_fiscalbr_inbox_documents (\n tenant_id, unit_id, access_key, nfe_number, nfe_series, nfe_model, issue_date,\n received_at, status, nature_operation, supplier_party_id, supplier_cnpj,\n supplier_name, supplier_ie, total_value, total_products, total_discount,\n total_freight, total_insurance, total_other, additional_info, metadata)\n VALUES (\n v_tenant, v_unit, v_key, p_note->>'nfe_number', p_note->>'nfe_series',\n coalesce(p_note->>'nfe_model', '55'), nullif(p_note->>'issue_date', '')::date,\n now(), 'pending', p_note->>'nature_operation', v_party, nullif(v_cnpj, ''),\n p_note->'supplier'->>'name', p_note->'supplier'->>'ie',\n (p_note->'totals'->>'total')::numeric, (p_note->'totals'->>'products')::numeric,\n (p_note->'totals'->>'discount')::numeric, (p_note->'totals'->>'freight')::numeric,\n (p_note->'totals'->>'insurance')::numeric, (p_note->'totals'->>'other')::numeric,\n p_note->>'additional_info',\n jsonb_build_object('source', coalesce(p_note->>'source', 'xml_upload')))\n -- O índice único da 002 é PARCIAL (\\`WHERE access_key IS NOT NULL\\`), e a\n -- inferência do ON CONFLICT só o alcança repetindo o predicado. Sem ele o\n -- INSERT levanta «no unique or exclusion constraint matching» — e levantaria\n -- na primeira reimportação, não na aplicação.\n ON CONFLICT (tenant_id, access_key) WHERE access_key IS NOT NULL DO UPDATE SET\n -- Reimportar o mesmo XML corrige o cabeçalho; a contraparte só é preenchida\n -- quando está vazia, para não desfazer uma costura feita à mão.\n nfe_number = EXCLUDED.nfe_number,\n nature_operation = coalesce(EXCLUDED.nature_operation, public.plg_fiscalbr_inbox_documents.nature_operation),\n supplier_party_id = coalesce(public.plg_fiscalbr_inbox_documents.supplier_party_id, EXCLUDED.supplier_party_id),\n supplier_name = EXCLUDED.supplier_name,\n total_value = EXCLUDED.total_value,\n updated_at = now()\n RETURNING * INTO v_doc;\n\n -- Os itens e as duplicatas são do DOCUMENTO, não do operador: vêm do XML e\n -- podem ser reescritos enquanto a nota não foi aceita.\n DELETE FROM public.plg_fiscalbr_inbox_items WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n DELETE FROM public.plg_fiscalbr_inbox_duplicates WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n DELETE FROM public.plg_fiscalbr_inbox_payments WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n FOR v_item IN SELECT * FROM jsonb_array_elements(coalesce(p_note->'items', '[]'::jsonb)) LOOP\n v_n := v_n + 1;\n\n -- O de-para: a segunda nota do mesmo fornecedor chega já vinculada. É o que\n -- faz importar XML valer a pena — sem ele toda nota recomeça do zero.\n SELECT * INTO v_map FROM public.plg_fiscalbr_supplier_product_map\n WHERE tenant_id = v_tenant AND supplier_cnpj = v_cnpj\n AND supplier_product_code = coalesce(v_item->>'supplier_product_code', '');\n IF FOUND THEN v_matched := v_matched + 1; END IF;\n\n INSERT INTO public.plg_fiscalbr_inbox_items (\n tenant_id, inbox_document_id, item_number, supplier_product_code, ean_barcode,\n description, ncm, cest, cfop, unit_commercial, quantity_commercial,\n unit_price_commercial, total_price, discount, freight, other_expenses,\n icms_cst, icms_csosn, icms_base, icms_rate, icms_value,\n pis_value, cofins_value, ipi_value, raw_xml_item,\n product_id, entry_type, chart_account_id, stock_unit_id, conversion_factor,\n cost_mode, reconciled, stock_quantity, unit_cost_new)\n VALUES (\n v_tenant, v_doc.id, coalesce((v_item->>'item_number')::int, v_n),\n v_item->>'supplier_product_code', v_item->>'ean_barcode',\n v_item->>'description', v_item->>'ncm', v_item->>'cest', v_item->>'cfop',\n v_item->>'unit', (v_item->>'quantity')::numeric,\n (v_item->>'unit_price')::numeric, (v_item->>'total')::numeric,\n (v_item->>'discount')::numeric, (v_item->>'freight')::numeric,\n (v_item->>'other')::numeric,\n v_item->>'icms_cst', v_item->>'icms_csosn', (v_item->>'icms_base')::numeric,\n (v_item->>'icms_rate')::numeric, (v_item->>'icms_value')::numeric,\n (v_item->>'pis_value')::numeric, (v_item->>'cofins_value')::numeric,\n (v_item->>'ipi_value')::numeric, v_item,\n v_map.product_id, v_map.entry_type, v_map.chart_account_id, v_map.stock_unit_id,\n coalesce(v_map.conversion_factor, 1), coalesce(v_map.cost_mode, 'novo'),\n v_map.product_id IS NOT NULL,\n -- A quantidade de estoque já sai calculada quando o de-para deu o fator: é\n -- o número que a tela mostra antes de aceitar.\n CASE WHEN v_map.product_id IS NOT NULL\n THEN (v_item->>'quantity')::numeric * coalesce(v_map.conversion_factor, 1) END,\n CASE WHEN v_map.product_id IS NOT NULL AND coalesce(v_map.conversion_factor, 1) > 0\n THEN (v_item->>'unit_price')::numeric / coalesce(v_map.conversion_factor, 1) END);\n END LOOP;\n\n INSERT INTO public.plg_fiscalbr_inbox_duplicates (\n tenant_id, inbox_document_id, duplicate_index, number, due_date, value, payment_type)\n SELECT v_tenant, v_doc.id, coalesce((d->>'index')::int, ord), d->>'number',\n nullif(d->>'due_date', '')::date, (d->>'value')::numeric,\n nullif(d->>'payment_type', '')\n FROM jsonb_array_elements(coalesce(p_note->'duplicates', '[]'::jsonb)) WITH ORDINALITY AS t(d, ord);\n\n INSERT INTO public.plg_fiscalbr_inbox_payments (\n tenant_id, inbox_document_id, payment_index, payment_indicator,\n payment_type_code, payment_type_label, value)\n SELECT v_tenant, v_doc.id, coalesce((p->>'index')::int, ord), p->>'indicator',\n p->>'code', p->>'label', (p->>'value')::numeric\n FROM jsonb_array_elements(coalesce(p_note->'payments', '[]'::jsonb)) WITH ORDINALITY AS t(p, ord);\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'access_key', v_key, 'already_accepted', false,\n 'supplier_party_id', v_party, 'items', v_n, 'matched', v_matched);\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_stage_inbox_document(jsonb) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_stage_inbox_document(jsonb) TO authenticated;\n\n-- ── Salvar a conciliação sem aceitar ───────────────────────────────────────\n--\n-- Conciliar e estocar são duas coisas no V1 — daí as duas colunas na lista, e\n-- daí a fila de 55 notas conciliadas e não estocadas. Quem salva o vínculo não\n-- está mandando dar entrada.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_save_inbox_decision(\n p_document_id uuid,\n p_items jsonb,\n p_default_chart_account_id uuid DEFAULT NULL,\n p_default_location_id uuid DEFAULT NULL,\n p_duplicates jsonb DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_row jsonb;\n v_done integer := 0;\n v_total integer;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.edit', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RAISE EXCEPTION 'fiscalbr: nota % já foi aceita — a decisão não muda depois do estoque', p_document_id\n USING ERRCODE = '23514';\n END IF;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n default_chart_account_id = coalesce(p_default_chart_account_id, default_chart_account_id),\n default_location_id = coalesce(p_default_location_id, default_location_id),\n reviewed_at = now(), updated_at = now()\n WHERE id = v_doc.id;\n\n FOR v_row IN SELECT * FROM jsonb_array_elements(coalesce(p_items, '[]'::jsonb)) LOOP\n UPDATE public.plg_fiscalbr_inbox_items i SET\n product_id = nullif(v_row->>'product_id', '')::uuid,\n entry_type = nullif(v_row->>'entry_type', ''),\n chart_account_id = nullif(v_row->>'chart_account_id', '')::uuid,\n stock_unit_id = nullif(v_row->>'stock_unit_id', '')::uuid,\n conversion_factor = coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1),\n cost_mode = coalesce(nullif(v_row->>'cost_mode', ''), 'novo'),\n shortage_quantity = nullif(v_row->>'shortage_quantity', '')::numeric,\n shortage_reason = nullif(v_row->>'shortage_reason', ''),\n shortage_note = nullif(v_row->>'shortage_note', ''),\n -- Derivadas, gravadas: é o que o operador viu.\n stock_quantity = i.quantity_commercial * coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1)\n - coalesce(nullif(v_row->>'shortage_quantity', '')::numeric, 0),\n unit_cost_new = CASE WHEN coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1) > 0\n THEN i.unit_price_commercial / coalesce(nullif(v_row->>'conversion_factor', '')::numeric, 1) END,\n -- Uma linha está conciliada quando sabe o que é. Despesa e serviço não\n -- pedem produto: elas nunca vão virar estoque.\n reconciled = CASE\n WHEN nullif(v_row->>'entry_type', '') IN ('despesa','servico') THEN true\n ELSE nullif(v_row->>'product_id', '') IS NOT NULL\n END,\n updated_at = now()\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.id = (v_row->>'id')::uuid;\n v_done := v_done + 1;\n END LOOP;\n\n IF p_duplicates IS NOT NULL THEN\n DELETE FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n INSERT INTO public.plg_fiscalbr_inbox_duplicates (\n tenant_id, inbox_document_id, duplicate_index, number, due_date, value,\n payment_type, barcode, pix_key, payment_method_id)\n SELECT v_tenant, v_doc.id, coalesce((d->>'index')::int, ord), d->>'number',\n nullif(d->>'due_date', '')::date, (d->>'value')::numeric,\n nullif(d->>'payment_type', ''), nullif(d->>'barcode', ''),\n nullif(d->>'pix_key', ''), nullif(d->>'payment_method_id', '')::uuid\n FROM jsonb_array_elements(p_duplicates) WITH ORDINALITY AS t(d, ord);\n END IF;\n\n SELECT count(*) INTO v_total FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET status = CASE\n WHEN (SELECT count(*) FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id AND reconciled) = v_total\n THEN 'accepted' ELSE 'partial' END\n WHERE id = v_doc.id;\n\n RETURN jsonb_build_object('document_id', v_doc.id, 'saved', v_done, 'items', v_total,\n 'reconciled', (SELECT count(*) FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id AND reconciled));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_save_inbox_decision(uuid, jsonb, uuid, uuid, jsonb) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_save_inbox_decision(uuid, jsonb, uuid, uuid, jsonb) TO authenticated;\n\n-- ── Aceitar: estoque e título, de uma vez ──────────────────────────────────\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_accept_inbox_document(\n p_document_id uuid,\n p_location_id uuid DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_loc uuid;\n v_lines jsonb := '[]'::jsonb;\n v_insts jsonb := '[]'::jsonb;\n v_recv jsonb;\n v_inv jsonb;\n v_it record;\n v_no integer := 0;\n v_total numeric := 0;\n v_stock_n integer := 0;\n v_key text;\n v_invoice uuid;\n -- Posição na lista de linhas → id do item da nota. \\`line_no\\` do movimento\n -- indexa este array direto.\n v_item_ids uuid[] := '{}';\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.create', v_doc.unit_id);\n\n -- Já aceita devolve o que aceitou. Não é erro: é a segunda vez que o operador\n -- clicou, e o AC7 diz que isso não pode dobrar nada.\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RETURN jsonb_build_object('document_id', v_doc.id, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'operation_id', v_doc.inventory_operation_id);\n END IF;\n\n v_loc := coalesce(p_location_id, v_doc.default_location_id);\n\n -- Toda linha tem de saber o que é. Aceitar uma nota com item sem tipo gravaria\n -- um título cujo rateio ninguém consegue explicar depois.\n IF EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND (entry_type IS NULL OR entry_type = '')) THEN\n RAISE EXCEPTION 'fiscalbr: há item sem tipo de registro — conciliar antes de aceitar'\n USING ERRCODE = '23514';\n END IF;\n\n -- As linhas que viram estoque. Despesa e serviço ficam fora daqui e entram só\n -- no título.\n FOR v_it IN\n SELECT * FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND entry_type IN ('insumo','revenda','patrimonio')\n ORDER BY item_number\n LOOP\n IF v_it.product_id IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: item % é % e não tem produto vinculado', v_it.item_number, v_it.entry_type\n USING ERRCODE = '23514';\n END IF;\n v_no := v_no + 1;\n -- A ordem desta lista É o \\`line_no\\` que o movimento vai carregar. Guardo o\n -- id da linha na mesma posição para devolver o movimento ao item sem\n -- reconsultar — e sem depender de casar por produto, que repete quando a\n -- mesma mercadoria vem em duas linhas da nota.\n v_item_ids := v_item_ids || v_it.id;\n v_lines := v_lines || jsonb_build_object(\n 'product_id', v_it.product_id,\n 'quantity', coalesce(v_it.stock_quantity, v_it.quantity_commercial * v_it.conversion_factor),\n 'unit_cost', coalesce(v_it.unit_cost_new, v_it.unit_price_commercial / v_it.conversion_factor),\n 'measurement_unit_id', v_it.stock_unit_id,\n 'notes', v_it.description);\n END LOOP;\n v_stock_n := v_no;\n\n IF v_stock_n > 0 THEN\n IF v_loc IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: a nota tem % linha(s) de estoque e nenhum local de estoque escolhido', v_stock_n\n USING ERRCODE = '22023';\n END IF;\n -- A chave de acesso é única por documento fiscal no Brasil: é a chave de\n -- idempotência natural, e é ela que faz o segundo clique não dobrar saldo.\n v_recv := public.inventory_receive(\n v_loc, v_lines,\n jsonb_build_object(\n 'supplier_id', v_doc.supplier_party_id,\n 'date', v_doc.issue_date,\n 'type', 'nfe',\n 'ref', 'NF-e ' || coalesce(v_doc.nfe_number, '?'),\n 'notes', 'Entrada via DANFE NF-e ' || coalesce(v_doc.nfe_number, '?')),\n 'nfe:' || v_doc.access_key);\n\n -- Cada movimento volta para a SUA linha. Guardar só no cabeçalho responderia\n -- «esta nota entrou?» e nunca «esta linha entrou?» — e é a segunda pergunta\n -- que a conciliação parcial faz.\n --\n -- \\`line_no\\` do movimento é a posição na lista que montei acima, e\n -- \\`v_item_ids\\` está na mesma ordem: um join, não uma varredura por posição.\n UPDATE public.plg_fiscalbr_inbox_items i\n SET stock_movement_id = m.movement_id, updated_at = now()\n FROM (\n SELECT v_item_ids[(mov->>'line_no')::int] AS item_id, (mov->>'id')::uuid AS movement_id\n FROM jsonb_array_elements(coalesce(v_recv->'movements', '[]'::jsonb)) AS t(mov)\n WHERE (mov->>'line_no') IS NOT NULL\n ) m\n WHERE i.tenant_id = v_tenant AND i.id = m.item_id;\n END IF;\n\n -- ── O título ─────────────────────────────────────────────────────────────\n -- Total = soma das PARCELAS (regra da financial/084). Nota sem duplicata vira\n -- uma parcela só, no vencimento que a nota declarar ou na emissão.\n SELECT coalesce(sum(value), 0),\n coalesce(jsonb_agg(jsonb_build_object(\n 'number', coalesce(duplicate_index, 1),\n 'due_date', coalesce(due_date, v_doc.issue_date, current_date),\n 'amount', round(value, 2),\n 'metadata', jsonb_strip_nulls(jsonb_build_object(\n 'barcode', barcode, 'pixKey', pix_key, 'paymentType', payment_type,\n 'danfeNumber', number))) ORDER BY duplicate_index), '[]'::jsonb)\n INTO v_total, v_insts\n FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n IF jsonb_array_length(v_insts) = 0 THEN\n v_total := round(coalesce(v_doc.total_value, 0), 2);\n v_insts := jsonb_build_array(jsonb_build_object(\n 'number', 1, 'due_date', coalesce(v_doc.issue_date, current_date), 'amount', v_total));\n ELSE\n v_total := round(v_total, 2);\n END IF;\n\n -- A MESMA chave da 084: nota já transformada em título pelo porte histórico\n -- não ganha um segundo aqui.\n v_key := 'danfe:' || v_doc.access_key;\n\n v_inv := public.financial_create_invoice(\n 'payable', v_total, v_doc.supplier_party_id, NULL, v_doc.unit_id, v_insts,\n v_doc.issue_date,\n 'NF-e ' || coalesce(v_doc.nfe_number, '?') || ' · ' || coalesce(v_doc.supplier_name, 'fornecedor'),\n NULL,\n jsonb_build_object(\n 'source', 'danfe',\n 'danfe', jsonb_strip_nulls(jsonb_build_object(\n 'accessKey', v_doc.access_key, 'number', v_doc.nfe_number,\n 'series', v_doc.nfe_series, 'supplierName', v_doc.supplier_name,\n 'supplierCnpj', v_doc.supplier_cnpj,\n -- O total da NOTA continua legível, mesmo quando difere do total do\n -- título. É a diferença que a 084 mediu em 6,3% das notas.\n 'noteTotal', v_doc.total_value,\n 'inboxDocumentId', v_doc.id))),\n v_key);\n v_invoice := (v_inv->>'invoice_id')::uuid;\n\n -- As linhas do título: TODOS os itens, inclusive despesa e serviço. É o que\n -- responde «de que essa conta é feita».\n INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)\n SELECT v_tenant, v_invoice, i.description, i.quantity_commercial, i.unit_price_commercial,\n round(coalesce(i.total_price, 0), 2), i.item_number,\n jsonb_strip_nulls(jsonb_build_object(\n 'itemKind', i.entry_type, 'referenceId', i.product_id,\n 'chartAccountId', i.chart_account_id, 'ncm', i.ncm, 'cfop', i.cfop,\n 'supplierProductCode', i.supplier_product_code))\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n ORDER BY i.item_number\n ON CONFLICT DO NOTHING;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n invoice_id = v_invoice,\n inventory_operation_id = coalesce((v_recv->>'operation_id')::uuid, inventory_operation_id),\n stocked_at = CASE WHEN v_stock_n > 0 THEN now() ELSE stocked_at END,\n status = 'accepted', updated_at = now()\n WHERE id = v_doc.id;\n\n -- ── O de-para aprende ────────────────────────────────────────────────────\n -- A decisão desta nota é o que faz a próxima do mesmo fornecedor chegar\n -- pronta. Guardar isto é o que separa «importei XML» de «o sistema sabe o meu\n -- fornecedor».\n INSERT INTO public.plg_fiscalbr_supplier_product_map (\n tenant_id, supplier_cnpj, supplier_product_code, product_id, entry_type,\n chart_account_id, stock_unit_id, conversion_factor, cost_mode, hit_count, last_used_at)\n SELECT v_tenant, v_doc.supplier_cnpj, i.supplier_product_code, i.product_id,\n i.entry_type, coalesce(i.chart_account_id, v_doc.default_chart_account_id),\n i.stock_unit_id, i.conversion_factor, i.cost_mode, 1, now()\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.product_id IS NOT NULL\n AND coalesce(v_doc.supplier_cnpj, '') <> ''\n AND coalesce(i.supplier_product_code, '') <> ''\n ON CONFLICT (tenant_id, supplier_cnpj, supplier_product_code) DO UPDATE SET\n product_id = EXCLUDED.product_id,\n entry_type = EXCLUDED.entry_type,\n chart_account_id = coalesce(EXCLUDED.chart_account_id, public.plg_fiscalbr_supplier_product_map.chart_account_id),\n stock_unit_id = coalesce(EXCLUDED.stock_unit_id, public.plg_fiscalbr_supplier_product_map.stock_unit_id),\n conversion_factor = EXCLUDED.conversion_factor,\n cost_mode = EXCLUDED.cost_mode,\n hit_count = public.plg_fiscalbr_supplier_product_map.hit_count + 1,\n last_used_at = now(),\n updated_at = now();\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'already_accepted', false,\n 'invoice_id', v_invoice, 'invoice_total', v_total,\n 'installments', jsonb_array_length(v_insts),\n 'operation_id', v_recv->>'operation_id',\n 'stock_lines', v_stock_n,\n 'movements', coalesce(v_recv->'movements', '[]'::jsonb));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) TO authenticated;\n\n-- ── Rejeitar ───────────────────────────────────────────────────────────────\n-- O rodapé do diálogo do V1 tem dois botões, e o outro também precisa existir:\n-- recusar a nota é dizer que ela não vira nada aqui — sem apagar o documento,\n-- que é fiscal e tem de continuar legível.\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_reject_inbox_document(\n p_document_id uuid, p_reason text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.edit', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RAISE EXCEPTION 'fiscalbr: nota % já virou estoque ou título — recusar não desfaz', p_document_id\n USING ERRCODE = '23514';\n END IF;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n status = 'rejected',\n metadata = metadata || jsonb_strip_nulls(jsonb_build_object('rejectReason', p_reason)),\n reviewed_at = now(), updated_at = now()\n WHERE id = v_doc.id;\n\n RETURN jsonb_build_object('document_id', v_doc.id, 'status', 'rejected');\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_reject_inbox_document(uuid, text) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_reject_inbox_document(uuid, text) TO authenticated;\n`\n\nexport const MIGRATION_010_A_DATA_DE_EMISSAO_E_INSTANTE_E_A_COMPETENCIA_E_DIA = `-- ---------------------------------------------------------------------------\n-- 010_a_data_de_emissao_e_instante_e_a_competencia_e_dia.sql\n--\n-- A 009 não conseguia aceitar nota nenhuma. Descoberto no primeiro teste com\n-- usuário logado de verdade, que é onde ela ia ser usada:\n--\n-- POST rpc/fiscalbr_accept_inbox_document → 404\n-- function public.financial_create_invoice(unknown, numeric, uuid, unknown,\n-- uuid, jsonb, timestamp with time zone, text, unknown, jsonb, text)\n-- does not exist\n--\n-- \\`plg_fiscalbr_inbox_documents.issue_date\\` é **timestamptz** — a NF-e declara um\n-- INSTANTE (\\`dhEmi\\`, com fuso), e a 002 preservou isso. Eu escrevi a chamada\n-- supondo \\`date\\`, e \\`financial_create_invoice\\` pede \\`p_competence_date date\\`.\n--\n-- Nenhum teste pegou porque nenhum podia: o SQL aplica, a função compila (o corpo\n-- de PL/pgSQL não resolve assinatura em CREATE), e o erro só existe na chamada.\n-- Foi preciso um usuário logado percorrendo o caminho.\n--\n-- ── Duas correções, não uma ────────────────────────────────────────────────\n--\n-- 1. \\`issue_date::date\\` onde a competência é pedida. Instante é quando a nota foi\n-- emitida; competência é o DIA a que o título pertence, e o mês do título vem\n-- dela — um \\`timestamptz\\` viajando para lá levaria fuso para dentro de uma\n-- conta contábil.\n--\n-- 2. **Todo argumento tipado na chamada.** A chamada posicional passava \\`'payable'\\`\n-- e \\`NULL\\` sem tipo, e o Postgres tem de adivinhar entre as sobrecargas. Adivinhar\n-- certo hoje e errado quando alguém acrescentar uma sobrecarga é o defeito que\n-- volta meses depois sem ninguém mexer neste arquivo. Agora vai \\`::text\\`,\n-- \\`::uuid\\`, \\`::date\\` em tudo.\n--\n-- Idempotente: só substitui o corpo de uma função.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.fiscalbr_accept_inbox_document(\n p_document_id uuid,\n p_location_id uuid DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$\nDECLARE\n v_tenant uuid := public.plg_financial_require_tenant();\n v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;\n v_loc uuid;\n v_lines jsonb := '[]'::jsonb;\n v_insts jsonb := '[]'::jsonb;\n v_recv jsonb;\n v_inv jsonb;\n v_it record;\n v_no integer := 0;\n v_total numeric := 0;\n v_stock_n integer := 0;\n v_key text;\n v_invoice uuid;\n v_item_ids uuid[] := '{}';\n -- A competência: o DIA da emissão, não o instante.\n v_competence date;\nBEGIN\n SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents\n WHERE tenant_id = v_tenant AND id = p_document_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'fiscalbr: nota % não encontrada neste tenant', p_document_id USING ERRCODE = 'P0002';\n END IF;\n PERFORM public.plg_financial_require_permission('financial.create', v_doc.unit_id);\n\n IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN\n RETURN jsonb_build_object('document_id', v_doc.id, 'already_accepted', true,\n 'invoice_id', v_doc.invoice_id, 'operation_id', v_doc.inventory_operation_id);\n END IF;\n\n v_loc := coalesce(p_location_id, v_doc.default_location_id);\n v_competence := (v_doc.issue_date)::date;\n\n IF EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND (entry_type IS NULL OR entry_type = '')) THEN\n RAISE EXCEPTION 'fiscalbr: há item sem tipo de registro — conciliar antes de aceitar'\n USING ERRCODE = '23514';\n END IF;\n\n FOR v_it IN\n SELECT * FROM public.plg_fiscalbr_inbox_items\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id\n AND entry_type IN ('insumo','revenda','patrimonio')\n ORDER BY item_number\n LOOP\n IF v_it.product_id IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: item % é % e não tem produto vinculado', v_it.item_number, v_it.entry_type\n USING ERRCODE = '23514';\n END IF;\n v_no := v_no + 1;\n v_item_ids := v_item_ids || v_it.id;\n v_lines := v_lines || jsonb_build_object(\n 'product_id', v_it.product_id,\n 'quantity', coalesce(v_it.stock_quantity, v_it.quantity_commercial * v_it.conversion_factor),\n 'unit_cost', coalesce(v_it.unit_cost_new, v_it.unit_price_commercial / v_it.conversion_factor),\n 'measurement_unit_id', v_it.stock_unit_id,\n 'notes', v_it.description);\n END LOOP;\n v_stock_n := v_no;\n\n IF v_stock_n > 0 THEN\n IF v_loc IS NULL THEN\n RAISE EXCEPTION 'fiscalbr: a nota tem % linha(s) de estoque e nenhum local de estoque escolhido', v_stock_n\n USING ERRCODE = '22023';\n END IF;\n v_recv := public.inventory_receive(\n v_loc::uuid,\n v_lines::jsonb,\n jsonb_build_object(\n 'supplier_id', v_doc.supplier_party_id,\n -- O documento do estoque também quer o DIA.\n 'date', v_competence,\n 'type', 'nfe',\n 'ref', 'NF-e ' || coalesce(v_doc.nfe_number, '?'),\n 'notes', 'Entrada via DANFE NF-e ' || coalesce(v_doc.nfe_number, '?')),\n ('nfe:' || v_doc.access_key)::text);\n\n UPDATE public.plg_fiscalbr_inbox_items i\n SET stock_movement_id = m.movement_id, updated_at = now()\n FROM (\n SELECT v_item_ids[(mov->>'line_no')::int] AS item_id, (mov->>'id')::uuid AS movement_id\n FROM jsonb_array_elements(coalesce(v_recv->'movements', '[]'::jsonb)) AS t(mov)\n WHERE (mov->>'line_no') IS NOT NULL\n ) m\n WHERE i.tenant_id = v_tenant AND i.id = m.item_id;\n END IF;\n\n SELECT coalesce(sum(value), 0),\n coalesce(jsonb_agg(jsonb_build_object(\n 'number', coalesce(duplicate_index, 1),\n 'due_date', coalesce(due_date, v_competence, current_date),\n 'amount', round(value, 2),\n 'metadata', jsonb_strip_nulls(jsonb_build_object(\n 'barcode', barcode, 'pixKey', pix_key, 'paymentType', payment_type,\n 'danfeNumber', number))) ORDER BY duplicate_index), '[]'::jsonb)\n INTO v_total, v_insts\n FROM public.plg_fiscalbr_inbox_duplicates\n WHERE tenant_id = v_tenant AND inbox_document_id = v_doc.id;\n\n IF jsonb_array_length(v_insts) = 0 THEN\n v_total := round(coalesce(v_doc.total_value, 0), 2);\n v_insts := jsonb_build_array(jsonb_build_object(\n 'number', 1, 'due_date', coalesce(v_competence, current_date), 'amount', v_total));\n ELSE\n v_total := round(v_total, 2);\n END IF;\n\n v_key := 'danfe:' || v_doc.access_key;\n\n -- TODO argumento tipado. A chamada posicional sem tipo obrigava o Postgres a\n -- adivinhar entre sobrecargas, e foi assim que esta função nasceu quebrada.\n v_inv := public.financial_create_invoice(\n 'payable'::text,\n v_total::numeric,\n v_doc.supplier_party_id::uuid,\n NULL::uuid,\n v_doc.unit_id::uuid,\n v_insts::jsonb,\n v_competence::date,\n ('NF-e ' || coalesce(v_doc.nfe_number, '?') || ' · ' || coalesce(v_doc.supplier_name, 'fornecedor'))::text,\n NULL::text,\n jsonb_build_object(\n 'source', 'danfe',\n 'danfe', jsonb_strip_nulls(jsonb_build_object(\n 'accessKey', v_doc.access_key, 'number', v_doc.nfe_number,\n 'series', v_doc.nfe_series, 'supplierName', v_doc.supplier_name,\n 'supplierCnpj', v_doc.supplier_cnpj,\n 'noteTotal', v_doc.total_value,\n 'inboxDocumentId', v_doc.id)))::jsonb,\n v_key::text);\n v_invoice := (v_inv->>'invoice_id')::uuid;\n\n INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)\n SELECT v_tenant, v_invoice, i.description, i.quantity_commercial, i.unit_price_commercial,\n round(coalesce(i.total_price, 0), 2), i.item_number,\n jsonb_strip_nulls(jsonb_build_object(\n 'itemKind', i.entry_type, 'referenceId', i.product_id,\n 'chartAccountId', i.chart_account_id, 'ncm', i.ncm, 'cfop', i.cfop,\n 'supplierProductCode', i.supplier_product_code))\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n ORDER BY i.item_number\n ON CONFLICT DO NOTHING;\n\n UPDATE public.plg_fiscalbr_inbox_documents SET\n invoice_id = v_invoice,\n inventory_operation_id = coalesce((v_recv->>'operation_id')::uuid, inventory_operation_id),\n stocked_at = CASE WHEN v_stock_n > 0 THEN now() ELSE stocked_at END,\n status = 'accepted', updated_at = now()\n WHERE id = v_doc.id;\n\n INSERT INTO public.plg_fiscalbr_supplier_product_map (\n tenant_id, supplier_cnpj, supplier_product_code, product_id, entry_type,\n chart_account_id, stock_unit_id, conversion_factor, cost_mode, hit_count, last_used_at)\n SELECT v_tenant, v_doc.supplier_cnpj, i.supplier_product_code, i.product_id,\n i.entry_type, coalesce(i.chart_account_id, v_doc.default_chart_account_id),\n i.stock_unit_id, i.conversion_factor, i.cost_mode, 1, now()\n FROM public.plg_fiscalbr_inbox_items i\n WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id\n AND i.product_id IS NOT NULL\n AND coalesce(v_doc.supplier_cnpj, '') <> ''\n AND coalesce(i.supplier_product_code, '') <> ''\n ON CONFLICT (tenant_id, supplier_cnpj, supplier_product_code) DO UPDATE SET\n product_id = EXCLUDED.product_id,\n entry_type = EXCLUDED.entry_type,\n chart_account_id = coalesce(EXCLUDED.chart_account_id, public.plg_fiscalbr_supplier_product_map.chart_account_id),\n stock_unit_id = coalesce(EXCLUDED.stock_unit_id, public.plg_fiscalbr_supplier_product_map.stock_unit_id),\n conversion_factor = EXCLUDED.conversion_factor,\n cost_mode = EXCLUDED.cost_mode,\n hit_count = public.plg_fiscalbr_supplier_product_map.hit_count + 1,\n last_used_at = now(),\n updated_at = now();\n\n RETURN jsonb_build_object(\n 'document_id', v_doc.id, 'already_accepted', false,\n 'invoice_id', v_invoice, 'invoice_total', v_total,\n 'installments', jsonb_array_length(v_insts),\n 'operation_id', v_recv->>'operation_id',\n 'stock_lines', v_stock_n,\n 'movements', coalesce(v_recv->'movements', '[]'::jsonb));\nEND $function$;\n\nREVOKE ALL ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.fiscalbr_accept_inbox_document(uuid, uuid) TO authenticated;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_preserve_terminal_results_and_recover_leases\", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },\n { id: \"002_a_nota_que_chega_tem_onde_esperar\", sql: MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR },\n { id: \"003_a_caixa_de_entrada_atravessa\", sql: MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA },\n { id: \"004_o_grupo_fiscal_do_v1_repete_nome\", sql: MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME },\n { id: \"005_a_nota_emitida_e_um_documento\", sql: MIGRATION_005_A_NOTA_EMITIDA_E_UM_DOCUMENTO },\n { id: \"006_o_grupo_fiscal_ganha_o_rail\", sql: MIGRATION_006_O_GRUPO_FISCAL_GANHA_O_RAIL },\n { id: \"007_a_rls_do_documento_passa_a_ser_legivel\", sql: MIGRATION_007_A_RLS_DO_DOCUMENTO_PASSA_A_SER_LEGIVEL },\n { id: \"008_a_nota_recebida_guarda_a_decisao_de_entrada\", sql: MIGRATION_008_A_NOTA_RECEBIDA_GUARDA_A_DECISAO_DE_ENTRADA },\n { id: \"009_aceitar_a_nota_escreve_estoque_e_titulo_de_uma_vez\", sql: MIGRATION_009_ACEITAR_A_NOTA_ESCREVE_ESTOQUE_E_TITULO_DE_UMA_VEZ },\n { id: \"010_a_data_de_emissao_e_instante_e_a_competencia_e_dia\", sql: MIGRATION_010_A_DATA_DE_EMISSAO_E_INSTANTE_E_A_COMPETENCIA_E_DIA },\n]\n","import type { EntityDef, PluginRegistryDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Grupos fiscais — a tributação que um produto herda.\n//\n// A tabela existe desde a 002 deste plugin e NUNCA teve tela: o grupo fiscal\n// de toda conta migrada estava no banco sem porta. Isto é a porta.\n//\n// O que ele responde é uma pergunta só, feita muitas vezes: com que imposto\n// este produto sai na nota. Agrupar é o ponto — sem grupo, CFOP, CST, origem e\n// três alíquotas seriam repetidos em cada produto, e mudar a regra de um\n// estado viraria uma edição em massa.\n//\n// A ordem dos campos segue a da nota: primeiro o que classifica a OPERAÇÃO\n// (CFOP), depois o ICMS, depois PIS/COFINS, e por último IBS/CBS — que é a\n// reforma tributária, e que já tem campo porque o V1 já tem.\n// ---------------------------------------------------------------------------\n\nconst taxGroupEntity: EntityDef = {\n name: 'Grupo fiscal',\n namePlural: 'Grupos fiscais',\n icon: 'ReceiptText',\n displayField: 'name',\n defaultSort: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [\n {\n id: 'identity', label: 'Identificação', columns: 2,\n description: 'O nome é como a casa chama o grupo («Bebida alcoólica», «Serviço isento») — o resto é o que a nota exige.',\n },\n { id: 'icms', label: 'ICMS', columns: 3 },\n { id: 'pis_cofins', label: 'PIS e COFINS', columns: 2 },\n {\n id: 'ibs_cbs', label: 'IBS e CBS', columns: 2,\n description: 'A reforma tributária. Em branco enquanto não for exigido da sua operação.',\n },\n { ...RECORD_GROUP },\n ],\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, searchable: true, group: 'identity', span: 2 },\n // O CFOP classifica a OPERAÇÃO (venda dentro do estado, fora, devolução) e\n // é o primeiro campo que o contador confere.\n { key: 'cfop', label: 'CFOP', type: 'text', showInTable: true, searchable: true, group: 'identity' },\n // CEST anda com a substituição tributária: só existe para quem está nela.\n { key: 'cest', label: 'CEST', type: 'text', showInTable: false, group: 'identity' },\n { key: 'benefitCode', label: 'Código de benefício', type: 'text', showInTable: false, group: 'identity' },\n\n // CST é do regime normal e CSOSN é do Simples — a casa usa UM dos dois, e\n // qual depende do regime dela, não deste grupo. Os dois ficam à vista de\n // propósito: esconder o que a conta não usa exigiria saber o regime aqui.\n { key: 'cst', label: 'CST', type: 'text', showInTable: true, group: 'icms' },\n { key: 'csosn', label: 'CSOSN (Simples)', type: 'text', showInTable: false, group: 'icms' },\n {\n key: 'icmsOrigin', label: 'Origem da mercadoria', type: 'select', showInTable: false, group: 'icms',\n options: [\n { value: '0', label: '0 — Nacional' },\n { value: '1', label: '1 — Estrangeira, importação direta' },\n { value: '2', label: '2 — Estrangeira, mercado interno' },\n { value: '3', label: '3 — Nacional, conteúdo de importação > 40%' },\n { value: '4', label: '4 — Nacional, processos produtivos básicos' },\n { value: '5', label: '5 — Nacional, conteúdo de importação ≤ 40%' },\n { value: '6', label: '6 — Estrangeira, sem similar nacional' },\n { value: '7', label: '7 — Estrangeira, mercado interno sem similar' },\n { value: '8', label: '8 — Nacional, conteúdo de importação > 70%' },\n ],\n },\n { key: 'icmsRate', label: 'Alíquota ICMS (%)', type: 'number', min: 0, max: 100, showInTable: true, group: 'icms' },\n { key: 'icmsBcMode', label: 'Modalidade da base', type: 'text', showInTable: false, group: 'icms' },\n { key: 'baseCalculationMode', label: 'Cálculo da base', type: 'text', showInTable: false, group: 'icms' },\n // O fundo de combate à pobreza é adicional ao ICMS em alguns estados.\n { key: 'povertyFundRate', label: 'Fundo de pobreza (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'icms' },\n\n { key: 'pisSituation', label: 'Situação PIS', type: 'text', showInTable: false, group: 'pis_cofins' },\n { key: 'pisRate', label: 'Alíquota PIS (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'pis_cofins' },\n { key: 'cofinsSituation', label: 'Situação COFINS', type: 'text', showInTable: false, group: 'pis_cofins' },\n { key: 'cofinsRate', label: 'Alíquota COFINS (%)', type: 'number', min: 0, max: 100, showInTable: false, group: 'pis_cofins' },\n\n { key: 'ibsCbsSituation', label: 'Situação IBS/CBS', type: 'text', showInTable: false, group: 'ibs_cbs' },\n { key: 'ibsCbsClassification', label: 'Classificação IBS/CBS', type: 'text', showInTable: false, group: 'ibs_cbs' },\n\n ...recordRailFields({ tagsTable: 'plg_fiscalbr_tax_groups', activeLabel: 'Ativo' }),\n ],\n data: {\n table: 'plg_fiscalbr_tax_groups',\n schema: 'public',\n tenantScoped: true,\n searchColumns: ['name', 'cfop'],\n },\n}\n\nexport const fiscalRegistries: PluginRegistryDef[] = [\n {\n id: 'taxGroups',\n icon: 'ReceiptText',\n entity: taxGroupEntity,\n description: 'A tributação que um produto herda: CFOP, ICMS, PIS/COFINS e, quando exigido, IBS/CBS.',\n agentHint: 'Regras de imposto que um produto herda — NÃO é a nota emitida nem o imposto de uma venda específica.',\n },\n]\n","// ---------------------------------------------------------------------------\n// nfe-xml — read a supplier NF-e (layout 4.00) into the shape the inbox wants.\n// ---------------------------------------------------------------------------\n// The XML is decomposed HERE, in TypeScript, and not in PL/pgSQL. Three reasons,\n// in order of how much each one cost when ignored elsewhere:\n//\n// 1. A parser with a unit test is a parser you can trust. The assertions in\n// nfe-xml.test.ts compare against what the V1 itself read out of the same\n// three documents, so drift is caught by the origin rather than by a number\n// someone typed into an expectation.\n// 2. A file that is not a nota has to produce a sentence the operator can act\n// on (\"this is an NFC-e, not a supplier note\"), and `RAISE EXCEPTION` from\n// a trigger deep in a transaction is not that sentence.\n// 3. The same reader runs in the browser, so the drop zone can show what it\n// found before anything is written.\n//\n// No XML dependency. The reader below is ~70 lines because NF-e is\n// machine-generated: no CDATA in the elements we read, no DTD, no mixed content.\n// Adding a parser to the dependency tree of every app that installs this plugin\n// to avoid those 70 lines is the worse trade.\n// ---------------------------------------------------------------------------\n\nexport interface NfeSupplier {\n cnpj: string\n name: string\n tradeName?: string\n ie?: string\n city?: string\n state?: string\n}\n\nexport interface NfeItem {\n itemNumber: number\n supplierProductCode: string\n eanBarcode?: string\n description: string\n ncm?: string\n cest?: string\n cfop?: string\n unit?: string\n quantity: number\n unitPrice: number\n total: number\n discount?: number\n freight?: number\n other?: number\n icmsCst?: string\n icmsCsosn?: string\n icmsOrigin?: string\n icmsBase?: number\n icmsRate?: number\n icmsValue?: number\n pisValue?: number\n cofinsValue?: number\n ipiValue?: number\n}\n\nexport interface NfeDuplicate {\n index: number\n number?: string\n dueDate?: string\n value: number\n}\n\nexport interface NfePayment {\n index: number\n indicator?: string\n code?: string\n label?: string\n value: number\n}\n\nexport interface NfeTotals {\n total: number\n products: number\n discount: number\n freight: number\n insurance: number\n other: number\n icmsBase?: number\n icmsValue?: number\n pisValue?: number\n cofinsValue?: number\n ipiValue?: number\n}\n\nexport interface ParsedNfe {\n accessKey: string\n nfeNumber: string\n nfeSeries: string\n nfeModel: string\n issueDate: string\n natureOperation?: string\n supplier: NfeSupplier\n totals: NfeTotals\n items: NfeItem[]\n duplicates: NfeDuplicate[]\n payments: NfePayment[]\n additionalInfo?: string\n protocol?: string\n authorizedAt?: string\n}\n\nexport class NfeParseError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'NfeParseError'\n }\n}\n\n// ── The reader ─────────────────────────────────────────────────────────────\n\ninterface XNode {\n name: string\n attrs: Record<string, string>\n children: XNode[]\n text: string\n}\n\nconst ENTITIES: Record<string, string> = {\n amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\",\n}\n\nfunction decode(raw: string): string {\n return raw.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (whole, body: string) => {\n if (body.startsWith('#x') || body.startsWith('#X')) return String.fromCodePoint(parseInt(body.slice(2), 16))\n if (body.startsWith('#')) return String.fromCodePoint(parseInt(body.slice(1), 10))\n return ENTITIES[body] ?? whole\n })\n}\n\n// Namespace prefixes are dropped: the whole document lives in the portalfiscal\n// namespace and a supplier that emits `ns2:infNFe` is emitting the same note.\nconst bare = (name: string) => {\n const i = name.indexOf(':')\n return i < 0 ? name : name.slice(i + 1)\n}\n\nfunction parseXml(xml: string): XNode {\n // Declaration, comments and processing instructions carry nothing we read.\n const src = xml\n .replace(/<\\?[\\s\\S]*?\\?>/g, '')\n .replace(/<!--[\\s\\S]*?-->/g, '')\n .replace(/<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>/g, (_m, inner: string) => inner)\n .replace(/<!DOCTYPE[^>]*>/gi, '')\n\n const root: XNode = { name: '#root', attrs: {}, children: [], text: '' }\n const stack: XNode[] = [root]\n const tag = /<\\s*(\\/?)\\s*([A-Za-z_][\\w.:-]*)((?:\\s+[\\w.:-]+\\s*=\\s*(?:\"[^\"]*\"|'[^']*'))*)\\s*(\\/?)\\s*>/g\n\n let cursor = 0\n let m: RegExpExecArray | null\n while ((m = tag.exec(src)) !== null) {\n const [whole, closing, rawName, rawAttrs, selfClosing] = m\n const top = stack[stack.length - 1]\n const between = src.slice(cursor, m.index)\n if (between.trim()) top.text += decode(between)\n cursor = m.index + whole.length\n\n if (closing) {\n if (stack.length > 1) stack.pop()\n continue\n }\n\n const attrs: Record<string, string> = {}\n const attrRe = /([\\w.:-]+)\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/g\n let a: RegExpExecArray | null\n while ((a = attrRe.exec(rawAttrs ?? '')) !== null) {\n attrs[bare(a[1])] = decode(a[2] ?? a[3] ?? '')\n }\n\n const node: XNode = { name: bare(rawName), attrs, children: [], text: '' }\n top.children.push(node)\n if (!selfClosing) stack.push(node)\n }\n return root\n}\n\nconst kids = (node: XNode | undefined, name: string): XNode[] =>\n node ? node.children.filter((c) => c.name === name) : []\n\nconst kid = (node: XNode | undefined, name: string): XNode | undefined => kids(node, name)[0]\n\n/** Walk a dot path (`ide.nNF`). Returns undefined at the first missing step. */\nfunction at(node: XNode | undefined, path: string): XNode | undefined {\n let cur = node\n for (const step of path.split('.')) {\n cur = kid(cur, step)\n if (!cur) return undefined\n }\n return cur\n}\n\nconst str = (node: XNode | undefined, path?: string): string | undefined => {\n const target = path ? at(node, path) : node\n const value = target?.text.trim()\n return value ? value : undefined\n}\n\n// The NF-e writes decimals with a dot and no thousands separator, so Number is\n// enough — but a missing tag must come back as undefined, not 0: a freight that\n// was not declared is not a freight of zero, and the difference shows up in the\n// total the payable is opened with.\nconst num = (node: XNode | undefined, path?: string): number | undefined => {\n const value = str(node, path)\n if (value === undefined) return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nconst zero = (node: XNode | undefined, path?: string): number => num(node, path) ?? 0\n\n// ── tPag → the V1's own payment vocabulary ─────────────────────────────────\n//\n// Table from NF-e 4.00 layout, collapsed onto the ten values V1 actually stores\n// (measured in `danfe_payments.payment_type`). Anything unmapped becomes\n// `outro`, which is what the V1 does with 107 of its 1.069 rows.\nconst PAYMENT_BY_CODE: Record<string, string> = {\n '01': 'dinheiro',\n '02': 'outro', // cheque\n '03': 'cartao_credito',\n '04': 'cartao_debito',\n '05': 'credito_loja',\n '10': 'outro', // vale alimentação\n '11': 'outro', // vale refeição\n '12': 'vale_presente',\n '13': 'outro', // vale combustível\n '14': 'duplicata_mercantil',\n '15': 'boleto',\n '16': 'outro', // depósito bancário\n '17': 'pix',\n '18': 'outro', // transferência bancária\n '19': 'outro', // programa de fidelidade\n '90': 'sem_pagamento',\n '99': 'outro',\n}\n\nconst PAYMENT_LABEL: Record<string, string> = {\n dinheiro: 'Dinheiro',\n cartao_credito: 'Cartão de crédito',\n cartao_debito: 'Cartão de débito',\n credito_loja: 'Crédito na loja',\n vale_presente: 'Vale presente',\n duplicata_mercantil: 'Duplicata mercantil',\n boleto: 'Boleto',\n pix: 'PIX',\n sem_pagamento: 'Sem pagamento',\n outro: 'Outro',\n}\n\n/** The V1's payment vocabulary for an NF-e `tPag` code. */\nexport function paymentTypeFromCode(code: string | undefined): string {\n if (!code) return 'outro'\n return PAYMENT_BY_CODE[code.padStart(2, '0')] ?? 'outro'\n}\n\nexport function paymentLabel(type: string): string {\n return PAYMENT_LABEL[type] ?? 'Outro'\n}\n\nexport const onlyDigits = (value: string | undefined): string => (value ?? '').replace(/\\D+/g, '')\n\n// ── The note ───────────────────────────────────────────────────────────────\n\n/**\n * Read a supplier NF-e. Accepts both the standalone `<NFe>` and the\n * `<nfeProc>` envelope the SEFAZ returns (which is what PlugNotas delivers and\n * what the V1 has stored for all 80 of Artorius' notes).\n */\nexport function parseNfeXml(xml: string): ParsedNfe {\n if (!xml || !xml.trim()) throw new NfeParseError('O arquivo está vazio.')\n\n const root = parseXml(xml)\n const proc = kid(root, 'nfeProc')\n const nfe = kid(proc ?? root, 'NFe') ?? kid(root, 'NFe')\n const inf = kid(nfe, 'infNFe')\n\n if (!inf) {\n throw new NfeParseError(\n 'Este arquivo não é uma NF-e: não encontrei <infNFe>. Se veio do fornecedor, peça o XML da nota, não o DANFE em PDF.',\n )\n }\n\n // The access key lives in the Id attribute as \"NFe\" + 44 digits. It is the\n // identity of the document — every idempotency key downstream derives from it.\n const accessKey = onlyDigits(inf.attrs.Id ?? inf.attrs.id ?? '')\n if (accessKey.length !== 44) {\n throw new NfeParseError(\n `A chave de acesso tem ${accessKey.length} dígitos e deveria ter 44. O arquivo pode estar truncado.`,\n )\n }\n\n const ide = kid(inf, 'ide')\n const model = str(ide, 'mod') ?? '55'\n if (model !== '55') {\n // 65 is NFC-e — a note the shop ISSUES at the till, not one a supplier sends.\n // Letting it through would open a payable against the shop's own customer.\n throw new NfeParseError(\n `Este XML é modelo ${model}${model === '65' ? ' (NFC-e, nota de venda no balcão)' : ''}, e a entrada de notas recebe NF-e modelo 55 de fornecedor.`,\n )\n }\n\n const emit = kid(inf, 'emit')\n const ender = kid(emit, 'enderEmit')\n const total = at(inf, 'total.ICMSTot')\n const dhEmi = str(ide, 'dhEmi') ?? str(ide, 'dEmi') ?? ''\n\n const items: NfeItem[] = kids(inf, 'det').map((det, i) => {\n const prod = kid(det, 'prod')\n const imposto = kid(det, 'imposto')\n // ICMS carries exactly one child, and which one depends on the supplier's tax\n // regime: ICMS00/20/40/60/90 for the normal regime, ICMSSN101/102/… for\n // Simples Nacional. Reading \"the child, whichever it is\" costs one line and\n // survives a supplier changing regime; a list of names does not.\n const icms = kid(imposto, 'ICMS')?.children[0]\n const pis = kid(imposto, 'PIS')?.children[0]\n const cofins = kid(imposto, 'COFINS')?.children[0]\n const ipi = kid(kid(imposto, 'IPI'), 'IPITrib')\n\n return {\n itemNumber: Number(det.attrs.nItem ?? i + 1) || i + 1,\n supplierProductCode: str(prod, 'cProd') ?? '',\n eanBarcode: str(prod, 'cEAN'),\n description: str(prod, 'xProd') ?? '(sem descrição)',\n ncm: str(prod, 'NCM'),\n cest: str(prod, 'CEST'),\n cfop: str(prod, 'CFOP'),\n unit: str(prod, 'uCom'),\n quantity: zero(prod, 'qCom'),\n unitPrice: zero(prod, 'vUnCom'),\n total: zero(prod, 'vProd'),\n discount: num(prod, 'vDesc'),\n freight: num(prod, 'vFrete'),\n other: num(prod, 'vOutro'),\n icmsCst: str(icms, 'CST'),\n icmsCsosn: str(icms, 'CSOSN'),\n icmsOrigin: str(icms, 'orig'),\n icmsBase: num(icms, 'vBC'),\n icmsRate: num(icms, 'pICMS'),\n icmsValue: num(icms, 'vICMS'),\n pisValue: num(pis, 'vPIS'),\n cofinsValue: num(cofins, 'vCOFINS'),\n ipiValue: num(ipi, 'vIPI'),\n }\n })\n\n if (items.length === 0) {\n throw new NfeParseError('A nota não tem nenhum item — não há o que dar entrada.')\n }\n\n // `cobr > dup` is the instalment plan the supplier declared. It is the reason\n // importing the note replaces typing the bill: the vencimentos come from the\n // document. A note without `dup` is not an error — it is paid on sight, and\n // the accept RPC opens a single instalment for it.\n const cobr = kid(inf, 'cobr')\n const duplicates: NfeDuplicate[] = kids(cobr, 'dup').map((dup, i) => ({\n index: i + 1,\n number: str(dup, 'nDup'),\n dueDate: str(dup, 'dVenc'),\n value: zero(dup, 'vDup'),\n }))\n\n const payments: NfePayment[] = kids(kid(inf, 'pag'), 'detPag').map((det, i) => {\n const code = str(det, 'tPag')\n const type = paymentTypeFromCode(code)\n return {\n index: i + 1,\n indicator: str(det, 'indPag'),\n code,\n label: paymentLabel(type),\n value: zero(det, 'vPag'),\n }\n })\n\n const prot = at(proc, 'protNFe.infProt')\n\n return {\n accessKey,\n nfeNumber: str(ide, 'nNF') ?? '',\n nfeSeries: str(ide, 'serie') ?? '',\n nfeModel: model,\n // The layout writes an ISO instant with offset; the inbox stores a date.\n issueDate: dhEmi.slice(0, 10),\n natureOperation: str(ide, 'natOp'),\n supplier: {\n cnpj: onlyDigits(str(emit, 'CNPJ') ?? str(emit, 'CPF')),\n name: str(emit, 'xNome') ?? '',\n tradeName: str(emit, 'xFant'),\n ie: str(emit, 'IE'),\n city: str(ender, 'xMun'),\n state: str(ender, 'UF'),\n },\n totals: {\n total: zero(total, 'vNF'),\n products: zero(total, 'vProd'),\n discount: zero(total, 'vDesc'),\n freight: zero(total, 'vFrete'),\n insurance: zero(total, 'vSeg'),\n other: zero(total, 'vOutro'),\n icmsBase: num(total, 'vBC'),\n icmsValue: num(total, 'vICMS'),\n pisValue: num(total, 'vPIS'),\n cofinsValue: num(total, 'vCOFINS'),\n ipiValue: num(total, 'vIPI'),\n },\n items,\n duplicates,\n payments,\n additionalInfo: str(at(inf, 'infAdic'), 'infCpl'),\n protocol: str(prot, 'nProt'),\n authorizedAt: str(prot, 'dhRecbto'),\n }\n}\n\n// ── The payload the staging RPC wants ──────────────────────────────────────\n//\n// `fiscalbr_stage_inbox_document` takes snake_case jsonb, and the mapping lives\n// next to the parser so a renamed field breaks in one place instead of being\n// silently dropped into a column that stays null.\n\nexport function toStagePayload(note: ParsedNfe, options: { unitId?: string | null; source?: string } = {}) {\n return {\n access_key: note.accessKey,\n nfe_number: note.nfeNumber,\n nfe_series: note.nfeSeries,\n nfe_model: note.nfeModel,\n issue_date: note.issueDate,\n nature_operation: note.natureOperation ?? null,\n additional_info: note.additionalInfo ?? null,\n unit_id: options.unitId ?? null,\n source: options.source ?? 'xml_upload',\n supplier: {\n cnpj: note.supplier.cnpj,\n name: note.supplier.name,\n ie: note.supplier.ie ?? null,\n },\n totals: {\n total: note.totals.total,\n products: note.totals.products,\n discount: note.totals.discount,\n freight: note.totals.freight,\n insurance: note.totals.insurance,\n other: note.totals.other,\n },\n items: note.items.map((i) => ({\n item_number: i.itemNumber,\n supplier_product_code: i.supplierProductCode,\n ean_barcode: i.eanBarcode ?? null,\n description: i.description,\n ncm: i.ncm ?? null,\n cest: i.cest ?? null,\n cfop: i.cfop ?? null,\n unit: i.unit ?? null,\n quantity: i.quantity,\n unit_price: i.unitPrice,\n total: i.total,\n discount: i.discount ?? null,\n freight: i.freight ?? null,\n other: i.other ?? null,\n icms_cst: i.icmsCst ?? null,\n icms_csosn: i.icmsCsosn ?? null,\n icms_base: i.icmsBase ?? null,\n icms_rate: i.icmsRate ?? null,\n icms_value: i.icmsValue ?? null,\n pis_value: i.pisValue ?? null,\n cofins_value: i.cofinsValue ?? null,\n ipi_value: i.ipiValue ?? null,\n })),\n // The instalment carries the payment form the note declared, so the\n // reconciliation dialog opens with `Boleto` already chosen instead of blank.\n duplicates: note.duplicates.map((d) => ({\n index: d.index,\n number: d.number ?? null,\n due_date: d.dueDate ?? null,\n value: d.value,\n payment_type: note.payments.length === 1 ? paymentTypeFromCode(note.payments[0].code) : null,\n })),\n payments: note.payments.map((p) => ({\n index: p.index,\n indicator: p.indicator ?? null,\n code: p.code ?? null,\n label: p.label ?? null,\n value: p.value,\n })),\n }\n}\n","// ---------------------------------------------------------------------------\n// inbox — the data layer of Entrada de Notas.\n// ---------------------------------------------------------------------------\n// Reads go through PostgREST so RLS answers; every WRITE goes through one of the\n// four RPCs of migration 009. That split is the whole safety property of this\n// screen: the browser never inserts a stock movement or a payable, it asks the\n// database to do both in one transaction with an idempotency key derived from\n// the NF-e access key.\n//\n// Nothing here parses XML. `../lib/nfe-xml` does that, is unit-tested against\n// three real notes, and hands this module the payload the staging RPC wants.\n// ---------------------------------------------------------------------------\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\nimport { parseNfeXml, toStagePayload, type ParsedNfe } from '../lib/nfe-xml'\nimport type {\n InboxNote, InboxNoteDetail, InboxItem, InboxInstalment,\n InboxStatusFilter, AcceptResult, StageResult, ProductOption,\n MeasurementUnitOption, ChartAccountOption, StockLocationOption,\n} from '../types'\n\nfunction sb() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\n// ── Leitura ────────────────────────────────────────────────────────────────\n\n// The two states the V1 list shows side by side, and they are NOT the same\n// question: `reconciled/total` counts items bound to a product, `stocked_at`\n// says the entry happened. 55 notes in the V1 were reconciled and never\n// stocked — a single \"status\" column would have hidden all 55.\nconst NOTE_COLUMNS = `\n id, access_key, nfe_number, nfe_series, issue_date, received_at, status,\n manifestation_status, manifested_at, manifestation_attempts,\n nature_operation, supplier_name, supplier_cnpj, supplier_party_id,\n total_value, total_products, total_discount, total_freight,\n invoice_id, inventory_operation_id, stocked_at, reviewed_at,\n default_chart_account_id, default_location_id, unit_id, document_id, metadata,\n items:plg_fiscalbr_inbox_items(id, reconciled, entry_type),\n duplicates:plg_fiscalbr_inbox_duplicates(id, value)\n`\n\ninterface RawNote {\n items?: Array<{ id: string; reconciled: boolean | null; entry_type: string | null }>\n duplicates?: Array<{ id: string; value: number | string | null }>\n [key: string]: unknown\n}\n\nfunction rowToNote(row: RawNote): InboxNote {\n const items = row.items ?? []\n const duplicates = row.duplicates ?? []\n return {\n id: String(row.id),\n accessKey: String(row.access_key ?? ''),\n number: String(row.nfe_number ?? ''),\n series: String(row.nfe_series ?? ''),\n issueDate: (row.issue_date as string) ?? null,\n receivedAt: (row.received_at as string) ?? null,\n status: (row.status as string) ?? 'pending',\n manifestationStatus: (row.manifestation_status as string) ?? null,\n manifestedAt: (row.manifested_at as string) ?? null,\n manifestationAttempts: Number(row.manifestation_attempts ?? 0),\n natureOperation: (row.nature_operation as string) ?? null,\n supplierName: (row.supplier_name as string) ?? '',\n supplierCnpj: (row.supplier_cnpj as string) ?? null,\n supplierPartyId: (row.supplier_party_id as string) ?? null,\n total: Number(row.total_value ?? 0),\n itemCount: items.length,\n reconciledCount: items.filter((i) => i.reconciled).length,\n instalmentCount: duplicates.length,\n // The sum of instalments, because that is the total the payable is opened\n // with (financial/084) — showing the note total here would make the list and\n // Contas a Pagar disagree on 6,3% of notes.\n instalmentTotal: duplicates.reduce((acc, d) => acc + Number(d.value ?? 0), 0),\n invoiceId: (row.invoice_id as string) ?? null,\n operationId: (row.inventory_operation_id as string) ?? null,\n stockedAt: (row.stocked_at as string) ?? null,\n documentId: (row.document_id as string) ?? null,\n unitId: (row.unit_id as string) ?? null,\n }\n}\n\nexport async function listInboxNotes(options: {\n filter?: InboxStatusFilter\n search?: string\n /** Narrows to one unit. Omitted = every unit the person reaches (RLS fences\n * the rest), which is what the V1 list did on \"Todas as unidades\". */\n unitId?: string\n /** Emission window, YYYY-MM-DD and inclusive. */\n from?: string\n to?: string\n limit?: number\n} = {}): Promise<InboxNote[]> {\n const { filter = 'all', search, unitId, from, to, limit = 200 } = options\n let query = sb().from('plg_fiscalbr_inbox_documents').select(NOTE_COLUMNS)\n\n if (unitId) query = query.eq('unit_id', unitId)\n // A nota sem data de emissão não some do recorte: ela ainda não foi lida do\n // XML, e esconder o que falta ler é esconder o trabalho.\n if (from) query = query.or(`issue_date.gte.${from},issue_date.is.null`)\n if (to) query = query.or(`issue_date.lte.${to},issue_date.is.null`)\n\n // `stocked` and `pending` are about the STOCK column, not about `status`:\n // \"pendente\" in the V1 list means the entry has not happened, whatever the\n // reconciliation says.\n if (filter === 'stocked') query = query.not('stocked_at', 'is', null)\n if (filter === 'pending') query = query.is('stocked_at', null)\n if (filter === 'rejected') query = query.eq('status', 'rejected')\n if (filter === 'to_manifest') query = query.not('manifestation_status', 'eq', 'confirmada')\n if (search?.trim()) {\n const term = search.trim()\n query = query.or(\n `supplier_name.ilike.%${term}%,nfe_number.ilike.%${term}%,access_key.ilike.%${term}%`,\n )\n }\n\n const { data, error } = await query\n .order('issue_date', { ascending: false, nullsFirst: false })\n .order('received_at', { ascending: false })\n .limit(limit)\n if (error) throw error\n return (data ?? []).map(rowToNote)\n}\n\nconst ITEM_COLUMNS = `\n id, item_number, supplier_product_code, ean_barcode, description, ncm, cest, cfop,\n unit_commercial, quantity_commercial, unit_price_commercial, total_price, discount,\n icms_cst, icms_csosn, icms_base, icms_rate, icms_value, pis_value, cofins_value, ipi_value,\n product_id, entry_type, chart_account_id, stock_unit_id, stock_quantity,\n conversion_factor, cost_mode, unit_cost_new, reconciled, stock_movement_id,\n shortage_quantity, shortage_reason, shortage_note\n`\n\nfunction rowToItem(row: Record<string, any>): InboxItem {\n const quantity = Number(row.quantity_commercial ?? 0)\n const factor = Number(row.conversion_factor ?? 1) || 1\n return {\n id: String(row.id),\n itemNumber: Number(row.item_number ?? 0),\n supplierProductCode: row.supplier_product_code ?? '',\n eanBarcode: row.ean_barcode ?? null,\n description: row.description ?? '',\n ncm: row.ncm ?? null,\n cest: row.cest ?? null,\n cfop: row.cfop ?? null,\n unit: row.unit_commercial ?? null,\n quantity,\n unitPrice: Number(row.unit_price_commercial ?? 0),\n total: Number(row.total_price ?? 0),\n discount: row.discount == null ? null : Number(row.discount),\n icmsCst: row.icms_cst ?? null,\n icmsCsosn: row.icms_csosn ?? null,\n icmsValue: row.icms_value == null ? null : Number(row.icms_value),\n productId: row.product_id ?? null,\n entryType: row.entry_type ?? null,\n chartAccountId: row.chart_account_id ?? null,\n stockUnitId: row.stock_unit_id ?? null,\n conversionFactor: factor,\n // Derived AND stored by the RPC. Reading the stored value keeps the screen\n // showing the number the operator accepted, and falls back to the product of\n // the two only while the decision has not been saved yet.\n stockQuantity: row.stock_quantity == null ? quantity * factor : Number(row.stock_quantity),\n costMode: row.cost_mode ?? 'novo',\n unitCostNew: row.unit_cost_new == null ? null : Number(row.unit_cost_new),\n reconciled: Boolean(row.reconciled),\n stockMovementId: row.stock_movement_id ?? null,\n shortageQuantity: row.shortage_quantity == null ? null : Number(row.shortage_quantity),\n shortageReason: row.shortage_reason ?? null,\n shortageNote: row.shortage_note ?? null,\n }\n}\n\nexport async function getInboxNote(id: string): Promise<InboxNoteDetail | null> {\n const { data, error } = await sb()\n .from('plg_fiscalbr_inbox_documents')\n .select(NOTE_COLUMNS)\n .eq('id', id)\n .maybeSingle()\n if (error) throw error\n if (!data) return null\n\n const [items, instalments, payments] = await Promise.all([\n sb().from('plg_fiscalbr_inbox_items').select(ITEM_COLUMNS)\n .eq('inbox_document_id', id).order('item_number'),\n sb().from('plg_fiscalbr_inbox_duplicates')\n .select('id, duplicate_index, number, due_date, value, payment_type, barcode, pix_key, payment_method_id')\n .eq('inbox_document_id', id).order('duplicate_index'),\n sb().from('plg_fiscalbr_inbox_payments')\n .select('id, payment_index, payment_type_code, payment_type_label, value')\n .eq('inbox_document_id', id).order('payment_index'),\n ])\n if (items.error) throw items.error\n if (instalments.error) throw instalments.error\n\n return {\n ...rowToNote(data as RawNote),\n natureOperation: (data as any).nature_operation ?? null,\n defaultChartAccountId: (data as any).default_chart_account_id ?? null,\n defaultLocationId: (data as any).default_location_id ?? null,\n items: (items.data ?? []).map(rowToItem),\n instalments: (instalments.data ?? []).map((d: any): InboxInstalment => ({\n id: String(d.id),\n index: Number(d.duplicate_index ?? 0),\n number: d.number ?? null,\n dueDate: d.due_date ?? null,\n amount: Number(d.value ?? 0),\n paymentType: d.payment_type ?? null,\n barcode: d.barcode ?? null,\n pixKey: d.pix_key ?? null,\n paymentMethodId: d.payment_method_id ?? null,\n })),\n declaredPayments: (payments.data ?? []).map((p: any) => ({\n index: Number(p.payment_index ?? 0),\n code: p.payment_type_code ?? null,\n label: p.payment_type_label ?? null,\n value: Number(p.value ?? 0),\n })),\n }\n}\n\n// ── Escrita: sempre por RPC ────────────────────────────────────────────────\n\n/**\n * Read one XML file and stage it. Returns what the parser found together with\n * how many items the de-para already bound, because that is the number the drop\n * zone reports: \"3 itens, 2 já vinculados\" is the difference between a screen\n * that remembers the supplier and one that does not.\n */\nexport async function stageNoteFromXml(\n xml: string,\n options: { unitId?: string | null } = {},\n): Promise<StageResult & { parsed: ParsedNfe }> {\n const parsed = parseNfeXml(xml)\n const { data, error } = await sb().rpc('fiscalbr_stage_inbox_document', {\n p_note: toStagePayload(parsed, { unitId: options.unitId ?? null }),\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n documentId: String(res.document_id ?? ''),\n accessKey: String(res.access_key ?? parsed.accessKey),\n alreadyAccepted: Boolean(res.already_accepted),\n supplierPartyId: (res.supplier_party_id as string) ?? null,\n itemCount: Number(res.items ?? 0),\n matchedCount: Number(res.matched ?? 0),\n parsed,\n }\n}\n\nexport interface ItemDecisionInput {\n id: string\n productId?: string | null\n entryType?: string | null\n chartAccountId?: string | null\n stockUnitId?: string | null\n conversionFactor?: number\n costMode?: string | null\n shortageQuantity?: number | null\n shortageReason?: string | null\n shortageNote?: string | null\n}\n\nexport interface InstalmentInput {\n index: number\n number?: string | null\n dueDate?: string | null\n amount: number\n paymentType?: string | null\n barcode?: string | null\n pixKey?: string | null\n paymentMethodId?: string | null\n}\n\nexport async function saveNoteDecision(input: {\n documentId: string\n items: ItemDecisionInput[]\n defaultChartAccountId?: string | null\n defaultLocationId?: string | null\n instalments?: InstalmentInput[] | null\n}): Promise<{ saved: number; items: number; reconciled: number }> {\n const { data, error } = await sb().rpc('fiscalbr_save_inbox_decision', {\n p_document_id: input.documentId,\n p_items: input.items.map((i) => ({\n id: i.id,\n product_id: i.productId ?? null,\n entry_type: i.entryType ?? null,\n chart_account_id: i.chartAccountId ?? null,\n stock_unit_id: i.stockUnitId ?? null,\n conversion_factor: i.conversionFactor ?? 1,\n cost_mode: i.costMode ?? 'novo',\n shortage_quantity: i.shortageQuantity ?? null,\n shortage_reason: i.shortageReason ?? null,\n shortage_note: i.shortageNote ?? null,\n })),\n p_default_chart_account_id: input.defaultChartAccountId ?? null,\n p_default_location_id: input.defaultLocationId ?? null,\n p_duplicates: input.instalments\n ? input.instalments.map((d) => ({\n index: d.index,\n number: d.number ?? null,\n due_date: d.dueDate ?? null,\n value: d.amount,\n payment_type: d.paymentType ?? null,\n barcode: d.barcode ?? null,\n pix_key: d.pixKey ?? null,\n payment_method_id: d.paymentMethodId ?? null,\n }))\n : null,\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n saved: Number(res.saved ?? 0),\n items: Number(res.items ?? 0),\n reconciled: Number(res.reconciled ?? 0),\n }\n}\n\n/**\n * Accept: stock entry and payable, one transaction. `alreadyAccepted` coming\n * back true is not an error — it is the second click, and the RPC is idempotent\n * on the NF-e access key.\n */\nexport async function acceptNote(documentId: string, locationId?: string | null): Promise<AcceptResult> {\n const { data, error } = await sb().rpc('fiscalbr_accept_inbox_document', {\n p_document_id: documentId,\n p_location_id: locationId ?? null,\n })\n if (error) throw error\n const res = (data ?? {}) as Record<string, unknown>\n return {\n documentId: String(res.document_id ?? documentId),\n alreadyAccepted: Boolean(res.already_accepted),\n invoiceId: (res.invoice_id as string) ?? null,\n invoiceTotal: Number(res.invoice_total ?? 0),\n instalments: Number(res.installments ?? 0),\n operationId: (res.operation_id as string) ?? null,\n stockLines: Number(res.stock_lines ?? 0),\n }\n}\n\nexport async function rejectNote(documentId: string, reason?: string): Promise<void> {\n const { error } = await sb().rpc('fiscalbr_reject_inbox_document', {\n p_document_id: documentId,\n p_reason: reason ?? null,\n })\n if (error) throw error\n}\n\n// ── Os cadastros que a conciliação precisa ─────────────────────────────────\n\nexport async function searchProducts(term: string, limit = 20): Promise<ProductOption[]> {\n let query = sb().from('products')\n .select('id, name, sku, unit, cost, kind')\n .eq('is_active', true)\n .limit(limit)\n if (term.trim()) query = query.or(`name.ilike.%${term.trim()}%,sku.ilike.%${term.trim()}%`)\n const { data, error } = await query.order('name')\n if (error) throw error\n return (data ?? []).map((p: any) => ({\n id: String(p.id), name: p.name ?? '', sku: p.sku ?? null,\n unit: p.unit ?? null, cost: p.cost == null ? null : Number(p.cost), kind: p.kind ?? null,\n }))\n}\n\nexport async function listMeasurementUnits(): Promise<MeasurementUnitOption[]> {\n const { data, error } = await sb().from('plg_inventory_measurement_units')\n .select('id, name, abbreviation, is_base').eq('is_active', true).order('name')\n if (error) throw error\n return (data ?? []).map((u: any) => ({\n id: String(u.id), name: u.name ?? '', abbreviation: u.abbreviation ?? '',\n isBase: Boolean(u.is_base),\n }))\n}\n\n/**\n * Leaf accounts only. `kind` never existed on this table: PostgREST answered 400\n * to the whole query and the caught error left the picker silently empty.\n */\nexport async function listChartAccounts(): Promise<ChartAccountOption[]> {\n const { data, error } = await sb().from('plg_financial_chart_of_accounts')\n .select('id, code, name, account_type, node_type, parent_id, is_active').order('code')\n if (error) throw error\n const rows = (data ?? []).filter((a: any) => a.is_active !== false)\n const parents = new Set(rows.map((a: any) => a.parent_id).filter(Boolean).map(String))\n return rows\n .filter((a: any) => a.node_type !== 'group' && !parents.has(String(a.id)))\n .map((a: any) => ({\n id: String(a.id), code: a.code ?? '', name: a.name ?? '', kind: a.account_type ?? null,\n }))\n}\n\nexport async function listStockLocations(): Promise<StockLocationOption[]> {\n const { data, error } = await sb().from('plg_inventory_stock_locations')\n .select('id, name, unit_id, is_active').order('name')\n if (error) throw error\n return (data ?? [])\n .filter((l: any) => l.is_active !== false)\n .map((l: any) => ({ id: String(l.id), name: l.name ?? '', unitId: l.unit_id ?? null }))\n}\n\n/**\n * What the supplier catalogue already remembers. The reconciliation screen shows\n * it next to a bound product so the operator can tell a de-para hit from a\n * product that appeared out of nowhere.\n */\nexport async function listSupplierMap(supplierCnpj: string): Promise<Array<{\n supplierProductCode: string; productId: string; hitCount: number; lastUsedAt: string | null\n}>> {\n if (!supplierCnpj) return []\n const { data, error } = await sb().from('plg_fiscalbr_supplier_product_map')\n .select('supplier_product_code, product_id, hit_count, last_used_at')\n .eq('supplier_cnpj', supplierCnpj)\n if (error) throw error\n return (data ?? []).map((m: any) => ({\n supplierProductCode: m.supplier_product_code ?? '',\n productId: String(m.product_id),\n hitCount: Number(m.hit_count ?? 0),\n lastUsedAt: m.last_used_at ?? null,\n }))\n}\n","// ---------------------------------------------------------------------------\n// Entrada de Notas — a lista, e a área onde o XML entra.\n// ---------------------------------------------------------------------------\n// Duas colunas de estado, e a diferença entre elas é o coração da tela:\n//\n// Conciliação quantos itens já sabem a que produto correspondem — 0/1, 1/1, 0/6\n// Estoque se a entrada aconteceu — Pendente / Estocado\n//\n// No V1 havia 55 notas conciliadas e nunca estocadas. Uma coluna de \"status\" só\n// teria escondido as 55, e a pergunta \"por que o estoque não mudou?\" não teria\n// resposta na tela.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { FileDown, Inbox, Loader2, Trash2, UploadCloud } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport {\n Button, Card, DataTable, FilterPanel, FilterPanelField, PageHeaderActions, SearchField,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue, useFilterDraft,\n} from '@fayz-ai/ui'\nimport { useUnitFilter } from '@fayz-ai/admin'\nimport { listInboxNotes, stageNoteFromXml, rejectNote } from '../data/inbox'\nimport type { InboxNote, InboxStatusFilter } from '../types'\n\nconst money = (value: number) =>\n new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value || 0)\n\nconst day = (iso: string | null) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\nconst cnpj = (digits: string | null) => {\n const d = (digits ?? '').replace(/\\D/g, '')\n if (d.length !== 14) return digits ?? '—'\n return `${d.slice(0, 2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${d.slice(12)}`\n}\n\nconst CAMPO = 'h-9 w-full rounded-md border border-input bg-background px-2 text-sm'\n\n/** O recorte, como ele vai para a consulta. */\ninterface Recorte {\n filter: InboxStatusFilter\n unitId: string\n from: string\n to: string\n}\n\nconst STATE_OPTIONS: Array<{ value: InboxStatusFilter; label: string }> = [\n { value: 'all', label: 'Todos' },\n { value: 'pending', label: 'Estoque pendente' },\n { value: 'stocked', label: 'Estocado' },\n { value: 'to_manifest', label: 'A manifestar' },\n { value: 'rejected', label: 'Recusada' },\n]\n\nconst isoDay = (d: Date) => d.toISOString().slice(0, 10)\n\n/** O resultado de arrastar um lote: o que entrou, o que o de-para já resolveu, o que recusou. */\ninterface DropReport {\n ok: Array<{ file: string; number: string; items: number; matched: number; repeated: boolean }>\n failed: Array<{ file: string; message: string }>\n}\n\nexport interface InboundNotesViewProps {\n /** Abre a conciliação da nota. A rota é do host — esta tela não sabe navegar. */\n onOpenNote: (noteId: string) => void\n onOpenManifest?: () => void\n}\n\nexport function InboundNotesView({ onOpenNote, onOpenManifest }: InboundNotesViewProps) {\n const [notes, setNotes] = useState<InboxNote[]>([])\n const [loading, setLoading] = useState(true)\n const [search, setSearch] = useState('')\n const [busy, setBusy] = useState(false)\n const [report, setReport] = useState<DropReport | null>(null)\n const [dragging, setDragging] = useState(false)\n const fileInput = useRef<HTMLInputElement>(null)\n\n // A unidade é o ALCANCE de quem olha: a lista abre na unidade em que a pessoa\n // está e só oferece as que ela alcança.\n const unidades = useUnitFilter({ scope: 'list' })\n\n // ── Rascunho e aplicado ─────────────────────────────────────────────────\n // O MESMO motor de recorte da conciliação bancária (FilterPanel): os campos\n // escrevem num rascunho e a lista só muda no «Buscar». Mexer em unidade,\n // estado e nas duas pontas do período seria quatro consultas no caminho, três\n // das quais ninguém pediu — e a terceira pode voltar depois da quarta e\n // pintar a tela com o recorte errado.\n const { draft, applied, patch, setDraft, dirty, apply, reset } = useFilterDraft<Recorte>({\n filter: 'all',\n unitId: unidades.value ?? '',\n // Sem período por padrão: o V1 abre em «Todos os registros», e uma janela\n // de 30 dias esconderia justamente a nota velha que nunca foi estocada.\n from: '',\n to: '',\n })\n\n // Trocar de unidade na casca re-ancora a lista, como no V1 quando a unidade\n // corrente mudava — e aplica na hora, porque uma lista presa ao recorte\n // anterior mostraria dados de outra unidade até alguém clicar em buscar.\n const ancora = unidades.value ?? ''\n const ancoraAnterior = useRef(ancora)\n useEffect(() => {\n if (ancoraAnterior.current === ancora) return\n ancoraAnterior.current = ancora\n setDraft((atual) => ({ ...atual, unitId: ancora }))\n apply()\n }, [ancora, setDraft, apply])\n const reload = useCallback(async () => {\n setLoading(true)\n try {\n setNotes(await listInboxNotes({\n filter: applied.filter,\n unitId: applied.unitId || undefined,\n from: applied.from || undefined,\n to: applied.to || undefined,\n }))\n } finally {\n setLoading(false)\n }\n }, [applied])\n\n useEffect(() => { void reload() }, [reload])\n\n // One file at a time, sequentially. The staging RPC is idempotent on the access\n // key, so a repeated file is not an error — but firing 20 of them in parallel\n // would race on the same de-para rows for the same supplier.\n const ingest = useCallback(async (files: File[]) => {\n const xmls = files.filter((f) => /\\.xml$/i.test(f.name))\n if (xmls.length === 0) {\n setReport({ ok: [], failed: [{ file: '—', message: 'Nenhum arquivo .xml no que foi solto.' }] })\n return\n }\n setBusy(true)\n const next: DropReport = { ok: [], failed: [] }\n for (const file of xmls) {\n try {\n const res = await stageNoteFromXml(await file.text())\n next.ok.push({\n file: file.name,\n number: res.parsed.nfeNumber,\n items: res.itemCount,\n matched: res.matchedCount,\n repeated: res.alreadyAccepted,\n })\n } catch (error) {\n next.failed.push({ file: file.name, message: error instanceof Error ? error.message : String(error) })\n }\n }\n setBusy(false)\n setReport(next)\n await reload()\n }, [reload])\n\n const remove = useCallback(async (note: InboxNote) => {\n // Recusar, não apagar: a nota é documento fiscal e continua legível.\n await rejectNote(note.id, 'Recusada na lista de entrada')\n await reload()\n }, [reload])\n\n const activeCount = (applied.filter === 'all' ? 0 : 1)\n + (applied.unitId ? 1 : 0)\n + (applied.from || applied.to ? 1 : 0)\n\n const limpar = useCallback(() => {\n reset({ filter: 'all', unitId: ancora, from: '', to: '' })\n }, [reset, ancora])\n\n /** As duas pontas nunca ficam invertidas: mexer numa arrasta a outra. */\n const setFrom = (from: string) => patch({ from, to: draft.to && from > draft.to ? from : draft.to })\n const setTo = (to: string) => patch({ to, from: draft.from && to < draft.from ? to : draft.from })\n\n // Local search: the list already arrives whole, so a round trip per keystroke buys nothing.\n const query = search.trim().toLowerCase()\n const shown = useMemo(() => {\n if (!query) return notes\n // CNPJ, access key and date match on digits, so punctuation never matters.\n const digits = query.replace(/\\D/g, '')\n return notes.filter((note) => {\n if (`${note.number} ${note.series} ${note.supplierName}`.toLowerCase().includes(query)) return true\n if (digits.length < 2) return false\n if ((note.supplierCnpj ?? '').replace(/\\D/g, '').includes(digits)) return true\n if ((note.accessKey ?? '').includes(digits)) return true\n return day(note.issueDate).replace(/\\D/g, '').includes(digits)\n })\n }, [notes, query])\n\n const columns = useMemo<ColumnDef<InboxNote, unknown>[]>(() => [\n {\n id: 'issueDate',\n header: 'Emissão',\n accessorFn: (note) => note.issueDate ?? '',\n cell: ({ row }) => <span className=\"tabular-nums text-muted-foreground\">{day(row.original.issueDate)}</span>,\n },\n {\n id: 'number',\n header: 'Nº',\n accessorFn: (note) => Number(note.number) || note.number,\n cell: ({ row }) => <span className=\"tabular-nums font-medium\">{row.original.number}</span>,\n },\n {\n id: 'supplier',\n header: 'Fornecedor',\n accessorFn: (note) => note.supplierName,\n cell: ({ row }) => (\n <div>\n <p className=\"font-medium leading-tight\">{row.original.supplierName || '—'}</p>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{cnpj(row.original.supplierCnpj)}</p>\n </div>\n ),\n },\n {\n id: 'items',\n header: () => <span className=\"block text-right\">Itens</span>,\n accessorFn: (note) => note.itemCount,\n cell: ({ row }) => (\n <span className=\"block text-right tabular-nums text-muted-foreground\">{row.original.itemCount}</span>\n ),\n },\n {\n id: 'reconciled',\n header: () => <span className=\"block text-center\">Conciliação</span>,\n accessorFn: (note) => (note.itemCount > 0 ? note.reconciledCount / note.itemCount : -1),\n cell: ({ row }) => (\n <div className=\"text-center\">\n <ReconcileBadge done={row.original.reconciledCount} total={row.original.itemCount} />\n </div>\n ),\n },\n {\n id: 'total',\n header: () => <span className=\"block text-right\">Valor</span>,\n accessorFn: (note) => note.total,\n cell: ({ row }) => {\n const note = row.original\n return (\n <div className=\"text-right tabular-nums\">\n {money(note.total)}\n {/* O título nasce com a soma das PARCELAS. Quando ela difere do\n total da nota, a tela mostra as duas — é a divergência que a\n conciliação passaria o mês procurando. */}\n {note.instalmentCount > 0 && Math.abs(note.instalmentTotal - note.total) > 0.01 && (\n <p className=\"text-[11px] text-warning-soft-foreground\">\n parcelas: {money(note.instalmentTotal)}\n </p>\n )}\n </div>\n )\n },\n },\n {\n id: 'stock',\n header: () => <span className=\"block text-center\">Estoque</span>,\n accessorFn: (note) => (note.stockedAt ? 2 : note.status === 'rejected' ? 0 : 1),\n cell: ({ row }) => (\n <div className=\"text-center\">\n <StockBadge stockedAt={row.original.stockedAt} status={row.original.status} />\n </div>\n ),\n },\n {\n id: 'actions',\n header: () => <span className=\"block text-right\">Ações</span>,\n enableSorting: false,\n cell: ({ row }) => {\n const note = row.original\n return (\n <div className=\"flex justify-end gap-1\">\n <Button size=\"sm\" variant={note.stockedAt ? 'ghost' : 'outline'} onClick={() => onOpenNote(note.id)}>\n {note.stockedAt ? 'Ver' : 'Conciliar'}\n </Button>\n {!note.stockedAt && !note.invoiceId && (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Recusar a nota ${note.number}`}\n onClick={() => { void remove(note) }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n )\n },\n },\n ], [onOpenNote, remove])\n\n // Empty-by-search and empty-by-no-notes have different fixes.\n const emptyMessage = query || activeCount > 0 ? (\n <div>\n <Inbox className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Nenhuma nota encontrada</p>\n <p className=\"text-xs text-muted-foreground\">Tente outro número, fornecedor ou CNPJ.</p>\n </div>\n ) : (\n <div>\n <Inbox className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Nenhuma nota de entrada</p>\n <p className=\"text-xs text-muted-foreground\">\n As notas chegam da SEFAZ pelo Manifesto, ou você arrasta o XML aqui.\n </p>\n </div>\n )\n\n return (\n <div className=\"space-y-4\">\n <PageHeaderActions>\n {onOpenManifest && (\n <Button variant=\"outline\" size=\"sm\" onClick={onOpenManifest}>\n <Inbox className=\"h-4 w-4 mr-1.5\" />\n Manifesto de Notas\n </Button>\n )}\n <Button size=\"sm\" onClick={() => fileInput.current?.click()} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 mr-1.5 animate-spin\" /> : <UploadCloud className=\"h-4 w-4 mr-1.5\" />}\n Importar XML\n </Button>\n </PageHeaderActions>\n\n {/* A área de arrastar é a porta de entrada, e o texto é o do V1: a entrada\n nasce do XML, não da digitação. */}\n <Card\n className={`border-dashed p-6 text-center transition-colors ${dragging ? 'border-primary bg-primary/5' : ''}`}\n onDragOver={(e: React.DragEvent) => { e.preventDefault(); setDragging(true) }}\n onDragLeave={() => setDragging(false)}\n onDrop={(e: React.DragEvent) => {\n e.preventDefault()\n setDragging(false)\n void ingest(Array.from(e.dataTransfer.files))\n }}\n >\n <UploadCloud className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Arraste arquivos XML aqui ou clique para selecionar</p>\n <p className=\"text-xs text-muted-foreground\">\n Suporta múltiplos arquivos XML de NF-e. O XML do fornecedor dá entrada no estoque e cria a conta a pagar.\n </p>\n <input\n ref={fileInput}\n type=\"file\"\n accept=\".xml,text/xml,application/xml\"\n multiple\n className=\"hidden\"\n onChange={(e) => {\n void ingest(Array.from(e.target.files ?? []))\n e.target.value = ''\n }}\n />\n </Card>\n\n {report && (\n <Card className=\"p-4 space-y-2\">\n {report.ok.map((r) => (\n <p key={r.file} className=\"text-sm\">\n <span className=\"font-medium\">NF-e {r.number}</span>{' '}\n <span className=\"text-muted-foreground\">\n {r.repeated\n ? '— já tinha sido aceita, nada mudou'\n // O número que diz se o de-para está trabalhando. Sem ele, o\n // operador não sabe se importar XML economizou algo.\n : `— ${r.items} ${r.items === 1 ? 'item' : 'itens'}, ${r.matched} já ${r.matched === 1 ? 'vinculado' : 'vinculados'}`}\n </span>\n </p>\n ))}\n {report.failed.map((r) => (\n <p key={r.file} className=\"text-sm text-destructive\">\n <span className=\"font-medium\">{r.file}</span> — {r.message}\n </p>\n ))}\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setReport(null)}>Fechar</Button>\n </Card>\n )}\n\n {/* ── O painel de filtros ──────────────────────────────────────────── */}\n {/* O MESMO FilterPanel da conciliação bancária: unidade, estado e as duas\n pontas do período definem O QUE se busca, e «Buscar» é que aplica.\n A BUSCA não entra aqui — ela é a barra da lista: quem digita está\n procurando UMA nota entre as que já estão na tela, não redefinindo a\n consulta. */}\n <FilterPanel\n title=\"Filtros\"\n dirty={dirty}\n onApply={apply}\n applyLabel=\"Buscar\"\n pendingTitle=\"Filtros não aplicados\"\n pendingHint=\"A lista ainda mostra o recorte anterior.\"\n onClear={activeCount > 0 ? limpar : undefined}\n clearLabel=\"Limpar\"\n busy={loading}\n >\n {unidades.visible && (\n <FilterPanelField label={unidades.label}>\n <Select\n value={draft.unitId || '__all__'}\n onValueChange={(v) => patch({ unitId: v === '__all__' ? '' : v })}\n >\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__all__\">{unidades.allLabel}</SelectItem>\n {unidades.options.map((u) => <SelectItem key={u.id} value={u.id}>{u.name}</SelectItem>)}\n </SelectContent>\n </Select>\n </FilterPanelField>\n )}\n\n <FilterPanelField label=\"Estado\">\n <Select value={draft.filter} onValueChange={(v) => patch({ filter: v as InboxStatusFilter })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {STATE_OPTIONS.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </FilterPanelField>\n\n <FilterPanelField label=\"Emissão de\">\n <input type=\"date\" value={draft.from} max={isoDay(new Date())} onChange={(e) => setFrom(e.target.value)} className={CAMPO} />\n </FilterPanelField>\n <FilterPanelField label=\"Emissão até\">\n <input type=\"date\" value={draft.to} max={isoDay(new Date())} onChange={(e) => setTo(e.target.value)} className={CAMPO} />\n </FilterPanelField>\n </FilterPanel>\n\n {/* Search and table are one surface — they act on the same rows. */}\n <Card className=\"overflow-hidden\">\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2\">\n <div className=\"min-w-[10rem] flex-1\">\n <SearchField\n value={search}\n onChange={setSearch}\n placeholder=\"Buscar por número, fornecedor, CNPJ…\"\n data-testid=\"inbound-notes-search\"\n />\n </div>\n </div>\n <DataTable\n variant=\"bare\"\n columns={columns}\n data={loading ? [] : shown}\n loading={loading}\n getRowId={(note) => note.id}\n emptyMessage={emptyMessage}\n />\n </Card>\n </div>\n )\n}\n\nfunction ReconcileBadge({ done, total }: { done: number; total: number }) {\n const full = total > 0 && done === total\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium tabular-nums ${\n full ? 'bg-success-soft text-success-soft-foreground' : 'bg-muted text-muted-foreground'\n }`}\n >\n {done}/{total}\n </span>\n )\n}\n\nfunction StockBadge({ stockedAt, status }: { stockedAt: string | null; status: string }) {\n if (status === 'rejected') {\n return <span className=\"inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground line-through\">Recusada</span>\n }\n return stockedAt ? (\n <span className=\"inline-flex items-center rounded-full bg-success-soft px-2 py-0.5 text-[11px] font-medium text-success-soft-foreground\">\n <FileDown className=\"mr-1 h-3 w-3\" aria-hidden />\n Estocado\n </span>\n ) : (\n <span className=\"inline-flex items-center rounded-full bg-warning-soft px-2 py-0.5 text-[11px] font-medium text-warning-soft-foreground\">\n Pendente\n </span>\n )\n}\n","/** The preview contract deliberately excludes production emission. */\nexport type PlugNotasEnvironment = 'sandbox' | 'homologation'\nexport type PlugNotasDocumentStatus = 'draft' | 'processing' | 'issued' | 'cancelled' | 'error'\n\nexport interface PlugNotasSetupState {\n emitterCnpj: string\n environment: PlugNotasEnvironment\n certificateReady: boolean\n cscReady: boolean\n providerEmitterId?: string\n certificateExpiresAt?: string\n certificateFingerprint?: string\n}\n\nexport interface PlugNotasDocumentResult {\n status: PlugNotasDocumentStatus\n providerDocumentId?: string\n integrationId?: string\n number?: string\n series?: string\n accessKey?: string\n message?: string\n}\n\nexport interface PlugNotasFiscalGateway {\n issue(input: { notaId: string; idempotencyKey: string }): Promise<PlugNotasDocumentResult>\n refresh(input: { notaId: string }): Promise<PlugNotasDocumentResult>\n cancel(input: { notaId: string; reason: string }): Promise<PlugNotasDocumentResult>\n artifact(input: {\n notaId: string\n kind: 'xml' | 'pdf' | 'cancellation_xml'\n }): Promise<{ url: string }>\n}\n\nexport interface PlugNotasConnectorClient {\n testEmitter?(input: {\n emitterCnpj: string\n environment: PlugNotasEnvironment\n }): Promise<{ ok: boolean; message?: string }>\n disconnectEmitter?(): Promise<void>\n}\n\nexport interface PlugNotasFinancialProviderOptions {\n base: import('@fayz-ai/plugin-financial').FinancialDataProvider\n gateway: PlugNotasFiscalGateway\n}\n\n// ---------------------------------------------------------------------------\n// Entrada de Notas — a nota que o fornecedor emitiu contra o CNPJ da casa.\n// ---------------------------------------------------------------------------\n// Dois estados, e eles NÃO respondem à mesma pergunta. `reconciledCount/itemCount`\n// diz quantos itens já sabem a que produto correspondem; `stockedAt` diz se a\n// entrada aconteceu. No V1 havia 55 notas conciliadas e nunca estocadas — uma\n// coluna de \"status\" só teria escondido as 55.\n\n/** Os cinco tipos de registro do V1, medidos em 3.402 linhas de produção. */\nexport type InboxEntryType = 'insumo' | 'revenda' | 'patrimonio' | 'despesa' | 'servico'\n\n/** Despesa e serviço nunca viram estoque: viram só título a pagar. */\nexport const STOCK_BEARING_ENTRY_TYPES: readonly InboxEntryType[] = ['insumo', 'revenda', 'patrimonio']\n\nexport const isStockBearing = (type: string | null | undefined): boolean =>\n STOCK_BEARING_ENTRY_TYPES.includes(type as InboxEntryType)\n\nexport type InboxCostMode = 'novo' | 'media'\n\nexport type InboxStatusFilter = 'all' | 'pending' | 'stocked' | 'rejected' | 'to_manifest'\n\nexport interface InboxNote {\n id: string\n accessKey: string\n number: string\n series: string\n issueDate: string | null\n receivedAt: string | null\n status: string\n manifestationStatus: string | null\n manifestedAt: string | null\n manifestationAttempts: number\n natureOperation: string | null\n supplierName: string\n supplierCnpj: string | null\n supplierPartyId: string | null\n /** O total declarado na NOTA. */\n total: number\n itemCount: number\n reconciledCount: number\n instalmentCount: number\n /** A soma das PARCELAS — é com este total que o título nasce (financial/084). */\n instalmentTotal: number\n invoiceId: string | null\n operationId: string | null\n stockedAt: string | null\n documentId: string | null\n unitId: string | null\n}\n\nexport interface InboxItem {\n id: string\n itemNumber: number\n supplierProductCode: string\n eanBarcode: string | null\n description: string\n ncm: string | null\n cest: string | null\n cfop: string | null\n unit: string | null\n quantity: number\n unitPrice: number\n total: number\n discount: number | null\n icmsCst: string | null\n icmsCsosn: string | null\n icmsValue: number | null\n productId: string | null\n entryType: string | null\n chartAccountId: string | null\n stockUnitId: string | null\n conversionFactor: number\n /** Quantidade × fator, menos a falta. É o número que a tela mostra ANTES de aceitar. */\n stockQuantity: number\n costMode: string\n unitCostNew: number | null\n reconciled: boolean\n stockMovementId: string | null\n shortageQuantity: number | null\n shortageReason: string | null\n shortageNote: string | null\n}\n\nexport interface InboxInstalment {\n id: string\n index: number\n number: string | null\n dueDate: string | null\n amount: number\n paymentType: string | null\n barcode: string | null\n pixKey: string | null\n paymentMethodId: string | null\n}\n\nexport interface InboxNoteDetail extends InboxNote {\n defaultChartAccountId: string | null\n defaultLocationId: string | null\n items: InboxItem[]\n instalments: InboxInstalment[]\n /** `pag > detPag` do XML: o que o fornecedor DECLAROU, não o que se decidiu. */\n declaredPayments: Array<{ index: number; code: string | null; label: string | null; value: number }>\n}\n\nexport interface StageResult {\n documentId: string\n accessKey: string\n alreadyAccepted: boolean\n supplierPartyId: string | null\n itemCount: number\n /** Quantos itens o de-para do fornecedor já vinculou sozinho. */\n matchedCount: number\n}\n\nexport interface AcceptResult {\n documentId: string\n /** `true` é o segundo clique, não um erro: a RPC é idempotente na chave de acesso. */\n alreadyAccepted: boolean\n invoiceId: string | null\n invoiceTotal: number\n instalments: number\n operationId: string | null\n stockLines: number\n}\n\nexport interface ProductOption {\n id: string\n name: string\n sku: string | null\n unit: string | null\n cost: number | null\n kind: string | null\n}\n\nexport interface MeasurementUnitOption {\n id: string\n name: string\n abbreviation: string\n isBase: boolean\n}\n\nexport interface ChartAccountOption {\n id: string\n code: string\n name: string\n kind: string | null\n}\n\nexport interface StockLocationOption {\n id: string\n name: string\n unitId: string | null\n}\n","// ---------------------------------------------------------------------------\n// Conciliação — onde a nota do fornecedor vira estoque e dinheiro.\n// ---------------------------------------------------------------------------\n// Os quatro blocos do V1, na mesma ordem: situação fiscal · itens · pagamento ·\n// anexos. O que mudou de forma, e por quê:\n//\n// O V1 põe isto num DIÁLOGO. Um diálogo com quatro blocos e uma grade de duas\n// colunas por item vira rolagem dentro de rolagem, e o item de baixo some\n// atrás do rodapé com «Aceitar» — exatamente o gesto que não pode ser dado no\n// escuro. Aqui é SUBPÁGINA, com `SubpageHeader` e «← Voltar», que é o idioma do\n// V2 para um fluxo inteiro. Mesma capacidade, mesma ordem, mesmo rodapé.\n//\n// A regra que a tela existe para cumprir: a **Qtd estoque (calc.)** muda na tela\n// ANTES de aceitar. O FLOW.md do V1 diz que fator de conversão errado é\n// silencioso e que esse número é a única defesa.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { AlertTriangle, Check, ChevronRight, Gift, Loader2, Plus, RefreshCw, Trash2, X } from 'lucide-react'\nimport { EmBreve } from './ComingSoon'\nimport {\n Button, Card, Input, SearchSelect, Skeleton, SubpageHeader, DatePicker, Hint,\n} from '@fayz-ai/ui'\nimport {\n getInboxNote, saveNoteDecision, acceptNote, rejectNote,\n searchProducts, listMeasurementUnits, listChartAccounts, listStockLocations,\n type ItemDecisionInput, type InstalmentInput,\n} from '../data/inbox'\nimport type { SearchSelectOption } from '@fayz-ai/ui'\nimport type {\n InboxNoteDetail, InboxItem, InboxEntryType,\n MeasurementUnitOption, ChartAccountOption, StockLocationOption, AcceptResult,\n} from '../types'\nimport { isStockBearing } from '../types'\n\nconst money = (v: number) => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(v || 0)\nconst qty = (v: number) => new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 4 }).format(v || 0)\nconst day = (iso: string | null | undefined) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\n// O vocabulário é o do V1, e a ordem é a de uso: insumo é 2.303 das 3.402 linhas.\nconst ENTRY_TYPES: Array<{ value: InboxEntryType; label: string; hint?: string }> = [\n { value: 'insumo', label: 'Insumo' },\n { value: 'revenda', label: 'Produto Revenda' },\n { value: 'patrimonio', label: 'Patrimônio' },\n { value: 'despesa', label: 'Despesa', hint: 'não vira estoque' },\n { value: 'servico', label: 'Serviço', hint: 'não vira estoque' },\n]\n\n/** O estado editável de uma linha. Espelha `ItemDecisionInput`, mais o que a tela calcula. */\ninterface Draft {\n productId: string | null\n productLabel: string\n entryType: InboxEntryType | null\n chartAccountId: string | null\n stockUnitId: string | null\n conversionFactor: string\n costMode: 'novo' | 'media'\n shortageQuantity: string\n}\n\n/**\n * `SearchSelect` não tem prop `options`: ele é sempre dirigido por busca — o que é\n * a escolha certa para produto (o catálogo tem 171) e continua servindo para as\n * listas curtas (plano de contas, unidade, local), filtrando em memória.\n */\nconst localSearch = (options: SearchSelectOption[]) => (query: string): SearchSelectOption[] => {\n const q = query.trim().toLowerCase()\n return (q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options).slice(0, 40)\n}\n\nconst labelOf = (options: SearchSelectOption[], id: string | null | undefined) =>\n options.find((o) => o.id === id)?.label\n\nconst draftOf = (item: InboxItem): Draft => ({\n productId: item.productId,\n productLabel: '',\n entryType: (item.entryType as InboxEntryType) ?? null,\n chartAccountId: item.chartAccountId,\n stockUnitId: item.stockUnitId,\n conversionFactor: String(item.conversionFactor ?? 1),\n costMode: (item.costMode === 'media' ? 'media' : 'novo'),\n shortageQuantity: item.shortageQuantity == null ? '' : String(item.shortageQuantity),\n})\n\nexport interface NoteReconcileViewProps {\n noteId: string\n onBack: () => void\n /** Onde o título a pagar abre depois de aceitar. O host sabe a rota; esta tela não. */\n onOpenInvoice?: (invoiceId: string) => void\n}\n\nexport function NoteReconcileView({ noteId, onBack, onOpenInvoice }: NoteReconcileViewProps) {\n const [note, setNote] = useState<InboxNoteDetail | null>(null)\n const [loading, setLoading] = useState(true)\n const [drafts, setDrafts] = useState<Record<string, Draft>>({})\n const [instalments, setInstalments] = useState<InstalmentInput[]>([])\n const [defaultAccount, setDefaultAccount] = useState<string | null>(null)\n const [location, setLocation] = useState<string | null>(null)\n const [units, setUnits] = useState<MeasurementUnitOption[]>([])\n const [accounts, setAccounts] = useState<ChartAccountOption[]>([])\n const [locations, setLocations] = useState<StockLocationOption[]>([])\n const [saving, setSaving] = useState(false)\n const [accepting, setAccepting] = useState(false)\n // One item open at a time: 11 expanded rows bury the one still missing a decision.\n const [openIds, setOpenIds] = useState<string[]>([])\n const [checked, setChecked] = useState<Record<string, boolean>>({})\n // A registry that fails to load leaves an empty picker, which reads as \"no data\".\n const [registryWarning, setRegistryWarning] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [accepted, setAccepted] = useState<AcceptResult | null>(null)\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n // A NOTA primeiro, e sozinha. Juntar tudo num `Promise.all` fazia a tela\n // MENTIR: bastava um dos três cadastros falhar para a promessa rejeitar, a\n // nota nunca ser atribuída, e a tela dizer «Nota não encontrada» sobre uma\n // nota que está lá. Foi o que aconteceu no primeiro E2E — a nota existia,\n // a consulta dela respondia 200, e a tela dizia que não existia.\n const detail = await getInboxNote(noteId)\n setNote(detail)\n\n // Os cadastros são para PREENCHER os seletores. Um que não carrega deixa um\n // seletor vazio — que é ruim, e é visível — em vez de esconder a nota.\n const failed: string[] = []\n const [u, a, l] = await Promise.all([\n listMeasurementUnits().catch(() => { failed.push('unidades'); return [] as MeasurementUnitOption[] }),\n listChartAccounts().catch(() => { failed.push('plano de contas'); return [] as ChartAccountOption[] }),\n listStockLocations().catch(() => { failed.push('locais de estoque'); return [] as StockLocationOption[] }),\n ])\n setUnits(u); setAccounts(a); setLocations(l)\n setRegistryWarning(failed.length ? `Não consegui carregar ${failed.join(', ')}. Estes seletores vão aparecer vazios.` : null)\n if (detail) {\n setDrafts(Object.fromEntries(detail.items.map((i) => [i.id, draftOf(i)])))\n // Server-side `reconciled` seeds the checks, so saving does not undo them.\n const done = Object.fromEntries(detail.items.filter((i) => i.reconciled).map((i) => [i.id, true]))\n setChecked((prev) => ({ ...prev, ...done }))\n const pending = detail.items.find((i) => !i.reconciled)\n setOpenIds(pending ? [pending.id] : [])\n setInstalments(detail.instalments.map((d) => ({\n index: d.index, number: d.number, dueDate: d.dueDate, amount: d.amount,\n paymentType: d.paymentType, barcode: d.barcode, pixKey: d.pixKey,\n })))\n setDefaultAccount(detail.defaultChartAccountId)\n setLocation(detail.defaultLocationId ?? l[0]?.id ?? null)\n }\n } catch (e) {\n // Falhar buscando a nota é diferente de não achar a nota, e a tela tem de\n // dizer qual dos dois foi.\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setLoading(false)\n }\n }, [noteId])\n\n useEffect(() => { void load() }, [load])\n\n const patch = (id: string, change: Partial<Draft>) =>\n setDrafts((prev) => ({ ...prev, [id]: { ...prev[id], ...change } }))\n\n const accountOptions = useMemo<SearchSelectOption[]>(\n () => accounts.map((a) => ({ id: a.id, label: `${a.code} · ${a.name}` })),\n [accounts],\n )\n const unitOptions = useMemo<SearchSelectOption[]>(\n () => units.map((u) => ({ id: u.id, label: u.abbreviation, subtitle: u.name })),\n [units],\n )\n const locationOptions = useMemo<SearchSelectOption[]>(\n () => locations.map((l) => ({ id: l.id, label: l.name })),\n [locations],\n )\n\n const decisions = useMemo((): ItemDecisionInput[] => {\n if (!note) return []\n return note.items.map((item) => {\n const d = drafts[item.id] ?? draftOf(item)\n return {\n id: item.id,\n productId: isStockBearing(d.entryType) ? d.productId : null,\n entryType: d.entryType,\n // A herança que a legenda do V1 promete: «itens sem plano herdarão este».\n chartAccountId: d.chartAccountId ?? defaultAccount,\n stockUnitId: d.stockUnitId,\n conversionFactor: Number(d.conversionFactor.replace(',', '.')) || 1,\n costMode: d.costMode,\n shortageQuantity: d.shortageQuantity === '' ? null : Number(d.shortageQuantity.replace(',', '.')),\n }\n })\n }, [note, drafts, defaultAccount])\n\n const stockLines = decisions.filter((d) => isStockBearing(d.entryType))\n const missingProduct = stockLines.filter((d) => !d.productId).length\n const missingType = decisions.filter((d) => !d.entryType).length\n const instalmentSum = instalments.reduce((acc, d) => acc + (Number(d.amount) || 0), 0)\n const readOnly = Boolean(note?.stockedAt || note?.invoiceId)\n\n // Same rule the save RPC uses for `reconciled`: checking adds no second state.\n const isReady = (d: Draft) => Boolean(d.entryType) && (!isStockBearing(d.entryType) || Boolean(d.productId))\n const doneCount = note ? note.items.filter((i) => checked[i.id]).length : 0\n\n const toggleItem = (id: string) =>\n setOpenIds((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]))\n\n /** Checking closes this item and opens the next pending one. */\n const confirmItem = (id: string) => {\n setChecked((prev) => ({ ...prev, [id]: true }))\n setOpenIds((prev) => {\n const rest = prev.filter((x) => x !== id)\n const next = note?.items.find((i) => i.id !== id && !checked[i.id])\n return next && !rest.includes(next.id) ? [...rest, next.id] : rest\n })\n }\n\n const save = async () => {\n if (!note) return\n setSaving(true); setError(null)\n try {\n await saveNoteDecision({\n documentId: note.id, items: decisions,\n defaultChartAccountId: defaultAccount, defaultLocationId: location,\n instalments,\n })\n await load()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setSaving(false)\n }\n }\n\n const accept = async () => {\n if (!note) return\n setAccepting(true); setError(null)\n try {\n // Salvar e aceitar num gesto: o operador clicou «Aceitar», e pedir que ele\n // salve antes seria uma etapa que só existe por causa do nosso desenho.\n await saveNoteDecision({\n documentId: note.id, items: decisions,\n defaultChartAccountId: defaultAccount, defaultLocationId: location,\n instalments,\n })\n setAccepted(await acceptNote(note.id, location))\n await load()\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setAccepting(false)\n }\n }\n\n // Skeleton mirrors the real layout so the page does not jump when it arrives.\n if (loading) {\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title=\"Conciliação\" onBack={onBack} parentLabel=\"Entrada de Notas\" />\n <Card className=\"p-4\">\n <Skeleton className=\"h-4 w-32\" />\n <div className=\"mt-3 grid gap-x-6 gap-y-3 sm:grid-cols-2 lg:grid-cols-3\">\n {[0, 1, 2, 3, 4, 5].map((i) => (\n <div key={i}>\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"mt-1.5 h-4 w-36\" />\n </div>\n ))}\n </div>\n </Card>\n <Card className=\"p-4\">\n <Skeleton className=\"h-4 w-36\" />\n <div className=\"mt-3 grid gap-4 sm:grid-cols-2\">\n {[0, 1].map((i) => (\n <div key={i}>\n <Skeleton className=\"h-3 w-28\" />\n <Skeleton className=\"mt-1.5 h-9 w-full\" />\n </div>\n ))}\n </div>\n </Card>\n <Skeleton className=\"h-4 w-24\" />\n <div className=\"space-y-2\">\n {[0, 1, 2].map((i) => (\n <Card key={i} className=\"flex items-center gap-3 px-4 py-3\">\n <Skeleton className=\"h-4 w-4 rounded-full\" />\n <div className=\"min-w-0 flex-1\">\n <Skeleton className=\"h-4 w-2/3\" />\n <Skeleton className=\"mt-1.5 h-3 w-1/3\" />\n </div>\n <Skeleton className=\"h-4 w-20\" />\n </Card>\n ))}\n </div>\n </div>\n )\n }\n\n if (!note) {\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title=\"Conciliação\" onBack={onBack} parentLabel=\"Entrada de Notas\" />\n <Card className=\"p-8 text-center text-sm\">\n {error\n ? <span className=\"text-destructive\">Não consegui carregar a nota: {error}</span>\n : <span className=\"text-muted-foreground\">Nota não encontrada.</span>}\n </Card>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4 pb-24\">\n <SubpageHeader\n title={`Conciliação · NF-e ${note.number}`}\n onBack={onBack}\n parentLabel=\"Entrada de Notas\"\n />\n\n {accepted && (\n <Card className=\"border-success bg-success-soft p-4\">\n <p className=\"text-sm font-medium text-success-soft-foreground\">\n {accepted.alreadyAccepted\n ? 'Esta nota já havia sido aceita — nada foi lançado de novo.'\n : `Aceita: ${accepted.stockLines} ${accepted.stockLines === 1 ? 'linha' : 'linhas'} de estoque e um título de ${money(accepted.invoiceTotal)} em ${accepted.instalments} ${accepted.instalments === 1 ? 'parcela' : 'parcelas'}.`}\n </p>\n {accepted.invoiceId && onOpenInvoice && (\n <Button variant=\"outline\" size=\"sm\" className=\"mt-2\" onClick={() => onOpenInvoice(accepted.invoiceId!)}>\n Abrir a conta a pagar\n </Button>\n )}\n </Card>\n )}\n\n {/* ── 1. Situação fiscal ─────────────────────────────────────────── */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Situação fiscal</h3>\n <dl className=\"mt-3 grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2 lg:grid-cols-3\">\n <Field label=\"Fornecedor\" value={note.supplierName || '—'} />\n <Field label=\"CNPJ\" value={note.supplierCnpj ?? '—'} mono />\n <Field label=\"Natureza da operação\" value={note.natureOperation ?? '—'} />\n <Field\n label=\"Manifestação\"\n value={`${note.manifestationStatus ?? 'não manifestada'}${note.manifestationAttempts ? ` · ${note.manifestationAttempts} tentativa(s)` : ''}`}\n />\n <Field label=\"Manifestada em\" value={day(note.manifestedAt)} />\n <Field label=\"Recebida em\" value={day(note.receivedAt)} />\n </dl>\n {/* O aviso é um bloco, não um trecho de texto: solto ele vazava do card e\n empurrava o botão para debaixo da própria frase. */}\n {!note.supplierPartyId && (\n <div className=\"mt-3 rounded-md border border-warning bg-warning-soft px-3 py-2\">\n <p className=\"text-xs text-warning-soft-foreground\">\n Este fornecedor não está no cadastro de pessoas, então o título a pagar vai nascer{' '}\n <strong>sem contraparte</strong>. Cadastre o CNPJ antes de aceitar para a conta saber a\n quem se deve.\n </p>\n </div>\n )}\n {/* A nota de bonificação entra no estoque e NÃO deve gerar título. Hoje\n gera: 57 notas assim no V1 da Artorius, em 11 grafias de natureza. */}\n {/bonific|brinde|doacao|doação/i.test(note.natureOperation ?? '') && (\n <div className=\"mt-3 rounded-md border border-dashed border-input px-3 py-2\">\n <p className=\"text-xs text-muted-foreground\">\n <Gift className=\"mr-1 inline h-3.5 w-3.5\" aria-hidden />\n A natureza desta nota é <strong>bonificação</strong>. Ela deveria entrar no estoque{' '}\n <strong>sem</strong> abrir conta a pagar — hoje ainda abre.{' '}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-[10px]\">Em breve</span>\n </p>\n </div>\n )}\n\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={() => { void load() }}>\n <RefreshCw className=\"mr-1.5 h-4 w-4\" />\n Atualizar status\n </Button>\n <EmBreve\n label=\"Cadastrar fornecedor\"\n o_que=\"Criar a pessoa do fornecedor aqui, sem sair da nota — é o que preenche a contraparte do título\"\n quantas=\"a Laissa cadastrou 37 fornecedores no V1 enquanto importava\"\n />\n </div>\n </Card>\n\n {/* ── 2. Padrões da nota ─────────────────────────────────────────── */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Padrões desta nota</h3>\n {registryWarning && (\n <div className=\"mt-2 rounded-md border border-warning bg-warning-soft px-3 py-2\">\n <p className=\"text-xs text-warning-soft-foreground\">\n <AlertTriangle className=\"mr-1 inline h-3.5 w-3.5\" aria-hidden />\n {registryWarning}\n </p>\n </div>\n )}\n <div className=\"mt-3 grid gap-4 sm:grid-cols-2\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Plano de contas padrão</span>\n <SearchSelect\n onSearch={localSearch(accountOptions)}\n value={defaultAccount ?? undefined}\n displayValue={labelOf(accountOptions, defaultAccount)}\n onChange={(id) => setDefaultAccount(id || null)}\n minChars={0}\n placeholder=\"Escolher plano de contas\"\n noResultsLabel=\"Nenhum plano de contas\"\n searchingLabel=\"Buscando…\"\n clearLabel=\"Limpar\"\n disabled={readOnly}\n />\n <span className=\"mt-1 block text-[11px] text-muted-foreground\">\n Itens sem plano herdarão este.\n </span>\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Local de estoque</span>\n <SearchSelect\n onSearch={localSearch(locationOptions)}\n value={location ?? undefined}\n displayValue={labelOf(locationOptions, location)}\n onChange={(id) => setLocation(id || null)}\n minChars={0}\n placeholder=\"Escolher local\"\n noResultsLabel=\"Nenhum local de estoque\"\n searchingLabel=\"Buscando…\"\n clearLabel=\"Limpar\"\n disabled={readOnly}\n />\n <span className=\"mt-1 block text-[11px] text-muted-foreground\">\n Onde as linhas de estoque desta nota entram.\n </span>\n </label>\n </div>\n </Card>\n\n {/* ── 3. Itens — one collapsed group per item, with progress ─────── */}\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h3 className=\"text-sm font-semibold\">\n Itens <span className=\"font-normal text-muted-foreground\">({note.items.length})</span>\n </h3>\n <div className=\"h-1.5 min-w-[6rem] flex-1 overflow-hidden rounded-full bg-muted\">\n <div\n className=\"h-full rounded-full bg-primary transition-all\"\n style={{ width: `${note.items.length ? (doneCount / note.items.length) * 100 : 0}%` }}\n />\n </div>\n <span className=\"text-xs tabular-nums text-muted-foreground\">\n {doneCount}/{note.items.length} conferidos\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setOpenIds(openIds.length ? [] : note.items.map((i) => i.id))}\n >\n {openIds.length ? 'Recolher todos' : 'Abrir todos'}\n </Button>\n </div>\n {note.items.map((item) => {\n const d = drafts[item.id] ?? draftOf(item)\n const factor = Number(d.conversionFactor.replace(',', '.')) || 1\n const shortage = d.shortageQuantity === '' ? 0 : Number(d.shortageQuantity.replace(',', '.')) || 0\n const stockQty = item.quantity * factor - shortage\n const unitCost = factor > 0 ? item.unitPrice / factor : item.unitPrice\n const bearing = isStockBearing(d.entryType)\n\n const open = openIds.includes(item.id)\n const done = Boolean(checked[item.id])\n const ready = isReady(d)\n const typeLabel = ENTRY_TYPES.find((t) => t.value === d.entryType)?.label\n\n return (\n <Card key={item.id} className=\"overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => toggleItem(item.id)}\n aria-expanded={open}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/30\"\n >\n <ChevronRight\n className={`h-4 w-4 shrink-0 text-muted-foreground transition-transform ${open ? 'rotate-90' : ''}`}\n aria-hidden\n />\n <span className=\"w-5 shrink-0 text-xs tabular-nums text-muted-foreground\">{item.itemNumber}</span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium leading-tight\">{item.description}</span>\n <span className=\"block truncate text-xs text-muted-foreground\">\n {qty(item.quantity)} {item.unit ?? ''} · {money(item.unitPrice)}\n {typeLabel ? ` · ${typeLabel}` : ' · sem tipo'}\n </span>\n </span>\n <span className=\"shrink-0 text-sm tabular-nums\">{money(item.total)}</span>\n <ItemState done={done} ready={ready} />\n </button>\n\n {open && (\n <div className=\"grid gap-4 border-t p-4 lg:grid-cols-2\">\n {/* ITEM NA NOTA — o que o documento diz, e não se edita. */}\n <div>\n <p className=\"text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Item na nota\n </p>\n <p className=\"mt-1 font-medium leading-tight\">{item.itemNumber}. {item.description}</p>\n <dl className=\"mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs sm:grid-cols-4\">\n <Field small label=\"Qtd\" value={`${qty(item.quantity)} ${item.unit ?? ''}`} />\n <Field small label=\"Vl. unit.\" value={money(item.unitPrice)} />\n <Field small label=\"Total\" value={money(item.total)} />\n <Field small label=\"Cód\" value={item.supplierProductCode || '—'} mono />\n <Field small label=\"EAN\" value={item.eanBarcode ?? '—'} mono />\n <Field small label=\"NCM\" value={item.ncm ?? '—'} mono />\n <Field small label=\"CFOP\" value={item.cfop ?? '—'} mono />\n <Field small label=\"CST/CSOSN\" value={item.icmsCst ?? item.icmsCsosn ?? '—'} mono />\n </dl>\n </div>\n\n {/* ITEM NO ESTOQUE — a decisão. */}\n <div className=\"space-y-3 lg:border-l lg:pl-4\">\n <p className=\"text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Item no estoque\n </p>\n\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Tipo do registro</span>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {ENTRY_TYPES.map((t) => (\n <button\n key={t.value}\n type=\"button\"\n disabled={readOnly}\n onClick={() => patch(item.id, { entryType: t.value })}\n className={`rounded-full border px-2.5 py-1 text-[11px] transition-colors disabled:opacity-60 ${\n d.entryType === t.value\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-input hover:bg-muted'\n }`}\n >\n {t.label}\n {t.hint && <span className=\"ml-1 opacity-70\">· {t.hint}</span>}\n </button>\n ))}\n </div>\n </label>\n\n {bearing && (\n <>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Produto vinculado</span>\n <SearchSelect\n value={d.productId ?? undefined}\n displayValue={d.productLabel || undefined}\n onChange={(id, option) =>\n patch(item.id, { productId: id || null, productLabel: option?.label ?? '' })}\n onSearch={async (term: string) => {\n // Busca vazia traz o que mais se parece com a descrição da\n // nota: o operador quase sempre quer justamente aquilo.\n const found = await searchProducts(term || item.description.slice(0, 24))\n return found.map((prod) => ({\n id: prod.id,\n label: prod.name,\n subtitle: prod.sku ?? undefined,\n }))\n }}\n minChars={0}\n placeholder=\"Buscar produto do catálogo\"\n noResultsLabel=\"Nenhum produto encontrado\"\n searchingLabel=\"Buscando…\"\n clearLabel=\"Limpar\"\n disabled={readOnly}\n />\n </label>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Fator de conversão</span>\n <Input\n value={d.conversionFactor}\n onChange={(e) => patch(item.id, { conversionFactor: e.target.value })}\n inputMode=\"decimal\"\n disabled={readOnly}\n />\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Unidade de estoque</span>\n <SearchSelect\n onSearch={localSearch(unitOptions)}\n value={d.stockUnitId ?? undefined}\n displayValue={labelOf(unitOptions, d.stockUnitId)}\n onChange={(id) => patch(item.id, { stockUnitId: id || null })}\n minChars={0}\n placeholder=\"Unidade\"\n noResultsLabel=\"Nenhuma unidade\"\n searchingLabel=\"Buscando…\"\n clearLabel=\"Limpar\"\n disabled={readOnly}\n />\n </label>\n </div>\n\n {/* A única defesa contra fator errado, e ela tem de ser\n legível ANTES de aceitar. */}\n <div className=\"rounded-md bg-muted/50 px-3 py-2\">\n <div className=\"flex items-baseline justify-between text-sm\">\n <span className=\"text-xs text-muted-foreground\">Qtd estoque (calc.)</span>\n <span className=\"font-semibold tabular-nums\">{qty(stockQty)}</span>\n </div>\n <div className=\"flex items-baseline justify-between text-sm\">\n <span className=\"text-xs text-muted-foreground\">Novo custo unitário</span>\n <span className=\"tabular-nums\">{money(unitCost)}</span>\n </div>\n </div>\n\n {/* Os dois gestos que hoje mandam a Laissa sair da tela. */}\n <div className=\"flex flex-wrap gap-2\">\n <EmBreve\n label=\"Criar produto daqui\"\n o_que=\"Cadastrar o produto a partir desta linha da nota, com nome, código e unidade já preenchidos\"\n quantas=\"ela criou 33 produtos no V1 no meio de importações\"\n />\n <EmBreve\n label=\"Lote e validade\"\n o_que=\"Informar lote e vencimento desta entrada — a coluna já existe no movimento de estoque\"\n quantas=\"usado 5 vezes no V1; numa churrascaria é validade de carne\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Modo de custo</span>\n <div className=\"mt-1 flex gap-1\">\n {(['novo', 'media'] as const).map((mode) => (\n <button\n key={mode}\n type=\"button\"\n disabled={readOnly}\n onClick={() => patch(item.id, { costMode: mode })}\n className={`flex-1 rounded-md border px-2 py-1 text-[11px] disabled:opacity-60 ${\n d.costMode === mode ? 'border-primary bg-primary/10' : 'border-input hover:bg-muted'\n }`}\n >\n {mode === 'novo' ? 'Novo' : 'Média'}\n </button>\n ))}\n </div>\n </label>\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Falta (qtd)</span>\n <Input\n value={d.shortageQuantity}\n onChange={(e) => patch(item.id, { shortageQuantity: e.target.value })}\n inputMode=\"decimal\"\n placeholder=\"0\"\n disabled={readOnly}\n />\n </label>\n </div>\n </>\n )}\n\n <label className=\"block\">\n <span className=\"text-xs font-medium text-muted-foreground\">Plano de contas</span>\n <SearchSelect\n onSearch={localSearch(accountOptions)}\n value={(d.chartAccountId ?? defaultAccount) ?? undefined}\n displayValue={labelOf(accountOptions, d.chartAccountId ?? defaultAccount)}\n onChange={(id) => patch(item.id, { chartAccountId: id || null })}\n minChars={0}\n placeholder=\"Herda o padrão da nota\"\n noResultsLabel=\"Nenhum plano de contas\"\n searchingLabel=\"Buscando…\"\n clearLabel=\"Limpar\"\n disabled={readOnly}\n />\n </label>\n\n {item.stockMovementId && (\n <p className=\"text-[11px] text-success-soft-foreground\">\n <Check className=\"mr-1 inline h-3 w-3\" aria-hidden />\n Esta linha já deu entrada no estoque.\n </p>\n )}\n\n {!readOnly && (\n <div className=\"flex items-center justify-end gap-3 border-t pt-3\">\n {!ready && (\n <span className=\"text-[11px] text-muted-foreground\">\n {!d.entryType ? 'Escolha o tipo do registro' : 'Vincule o produto'}\n </span>\n )}\n <Button\n size=\"sm\"\n variant={done ? 'ghost' : 'outline'}\n disabled={!ready}\n onClick={() => (done ? setChecked((prev) => ({ ...prev, [item.id]: false })) : confirmItem(item.id))}\n >\n <Check className=\"mr-1.5 h-4 w-4\" />\n {done ? 'Conferido' : 'Conferir item'}\n </Button>\n </div>\n )}\n </div>\n </div>\n )}\n </Card>\n )\n })}\n </div>\n\n {/* ── 4. Dados de pagamento ──────────────────────────────────────── */}\n <Card className=\"p-4\">\n <div className=\"flex items-baseline justify-between\">\n <h3 className=\"text-sm font-semibold\">Dados de pagamento</h3>\n <p className=\"text-xs text-muted-foreground\">\n {instalments.length} {instalments.length === 1 ? 'parcela' : 'parcelas'} ·{' '}\n <span className=\"tabular-nums\">{money(instalmentSum)}</span>\n </p>\n </div>\n\n {note.declaredPayments.length > 0 && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n A nota declarou: {note.declaredPayments.map((p) => `${p.label ?? p.code} ${money(p.value)}`).join(' · ')}\n </p>\n )}\n\n <div className=\"mt-3 space-y-2\">\n {instalments.map((inst, i) => (\n <div key={i} className=\"grid items-end gap-2 sm:grid-cols-[2rem_1fr_1fr_1fr_2rem]\">\n <span className=\"pb-2 text-xs tabular-nums text-muted-foreground\">{inst.index}</span>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Vencimento</span>\n {/* Nota já aceita não tem vencimento editável, e um seletor de data\n apagado confunde mais que o texto: a parcela virou título. */}\n {readOnly ? (\n <p className=\"py-2 text-sm tabular-nums\">{day(inst.dueDate)}</p>\n ) : (\n <DatePicker\n value={inst.dueDate ?? ''}\n onChange={(v: string) =>\n setInstalments((prev) => prev.map((p, j) => (j === i ? { ...p, dueDate: v || null } : p)))}\n />\n )}\n </label>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Valor</span>\n <Input\n value={String(inst.amount)}\n inputMode=\"decimal\"\n disabled={readOnly}\n onChange={(e) =>\n setInstalments((prev) => prev.map((p, j) =>\n (j === i ? { ...p, amount: Number(e.target.value.replace(',', '.')) || 0 } : p)))}\n />\n </label>\n <label className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">Cód. barras / PIX</span>\n <Input\n value={inst.barcode ?? inst.pixKey ?? ''}\n disabled={readOnly}\n onChange={(e) =>\n setInstalments((prev) => prev.map((p, j) => (j === i ? { ...p, barcode: e.target.value } : p)))}\n />\n </label>\n {!readOnly && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Remover a parcela ${inst.index}`}\n onClick={() => setInstalments((prev) => prev.filter((_, j) => j !== i))}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n ))}\n </div>\n\n {!readOnly && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => setInstalments((prev) => [...prev, {\n index: prev.length + 1, number: null, dueDate: note.issueDate, amount: 0, paymentType: 'boleto',\n }])}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n Adicionar parcela\n </Button>\n )}\n\n {/* O título nasce com a soma das parcelas. Se ela não bate com a nota, a\n tela diz — é a divergência que a financial/084 mediu em 6,3% dos casos. */}\n {Math.abs(instalmentSum - note.total) > 0.01 && (\n <Hint className=\"mt-3\">\n <span>\n <AlertTriangle className=\"mr-1 inline h-3.5 w-3.5\" aria-hidden />\n A nota diz {money(note.total)} e as parcelas somam {money(instalmentSum)}. O título vai\n nascer com <strong>{money(instalmentSum)}</strong> — é a soma das parcelas que define o\n saldo a pagar.\n </span>\n </Hint>\n )}\n </Card>\n\n {/* ── 5. Anexos da conta ─────────────────────────────────────────\n O quarto bloco do V1, e eu o tinha marcado como «adiado». Errado: a\n Laissa anexou 25 boletos no V1 e o último foi HOJE. A V2 já LÊ anexo\n (documents, subject_type='financial_invoice') e não tem escrita. */}\n <Card className=\"p-4\">\n <h3 className=\"text-sm font-semibold\">Anexos da conta</h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Boleto, comprovante, foto da nota. No sistema antigo, anexar o boleto também{' '}\n <strong>preenchia as parcelas sozinho</strong> — é a automação mais útil e a mais invisível de lá.\n </p>\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <EmBreve\n label=\"Anexar boleto\"\n o_que=\"Guardar o arquivo no título que esta nota cria\"\n quantas=\"25 anexos no V1, o último hoje\"\n />\n <EmBreve\n label=\"Ler o código de barras do boleto\"\n o_que=\"Preencher vencimento e valor da parcela a partir do boleto anexado\"\n quantas=\"automação do V1 que ninguém documentou\"\n />\n </div>\n </Card>\n\n {error && (\n <Card className=\"border-destructive bg-destructive/5 p-4\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </Card>\n )}\n\n {/* ── Rodapé: Rejeitar / Salvar / Aceitar ──────────────────────────\n `pr-16` abre espaço para o FAB do assistente, que flutua no canto e\n cobria metade do «Aceitar» — o gesto mais importante desta tela. */}\n {!readOnly && (\n <div className=\"sticky bottom-0 -mx-4 flex items-center justify-between gap-3 border-t bg-card/95 px-4 py-3 pr-16 backdrop-blur\">\n <Button\n variant=\"ghost\"\n onClick={async () => { await rejectNote(note.id); onBack() }}\n disabled={saving || accepting}\n >\n <X className=\"mr-1.5 h-4 w-4\" />\n Rejeitar\n </Button>\n\n <div className=\"flex items-center gap-2\">\n {(missingType > 0 || missingProduct > 0) && (\n <p className=\"text-xs text-muted-foreground\">\n {missingType > 0 && `${missingType} sem tipo`}\n {missingType > 0 && missingProduct > 0 && ' · '}\n {missingProduct > 0 && `${missingProduct} sem produto`}\n </p>\n )}\n <Button variant=\"outline\" onClick={() => { void save() }} disabled={saving || accepting}>\n {saving && <Loader2 className=\"mr-1.5 h-4 w-4 animate-spin\" />}\n Salvar conciliação\n </Button>\n <Button\n onClick={() => { void accept() }}\n disabled={accepting || saving || missingType > 0 || missingProduct > 0}\n >\n {accepting ? <Loader2 className=\"mr-1.5 h-4 w-4 animate-spin\" /> : <Check className=\"mr-1.5 h-4 w-4\" />}\n Aceitar\n </Button>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction ItemState({ done, ready }: { done: boolean; ready: boolean }) {\n if (done) {\n return (\n <span className=\"inline-flex shrink-0 items-center rounded-full bg-success-soft px-2 py-0.5 text-[11px] font-medium text-success-soft-foreground\">\n <Check className=\"mr-1 h-3 w-3\" aria-hidden />\n Conferido\n </span>\n )\n }\n return (\n <span className={`inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${\n ready ? 'bg-muted text-muted-foreground' : 'bg-warning-soft text-warning-soft-foreground'\n }`}>\n {ready ? 'A conferir' : 'Falta decidir'}\n </span>\n )\n}\n\nfunction Field({ label, value, mono, small }: { label: string; value: string; mono?: boolean; small?: boolean }) {\n return (\n <div>\n <dt className={`text-muted-foreground ${small ? 'text-[10px]' : 'text-xs'}`}>{label}</dt>\n <dd className={`${mono ? 'tabular-nums' : ''} ${small ? 'text-xs' : 'text-sm'}`}>{value}</dd>\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// Manifesto de Notas — as NF-e que fornecedores emitiram CONTRA o CNPJ da casa.\n// ---------------------------------------------------------------------------\n// Manifestar ≠ dar entrada. É a distinção que organiza todo o fiscal:\n//\n// Manifesto responde à SEFAZ · obrigação com prazo · aceitar/recusar\n// Entrada de Notas responde ao estoque e ao financeiro · conciliar item a item\n//\n// Duas filas, com dois tamanhos: no V1 havia 118 pendentes de manifestação e 55\n// de conciliação.\n//\n// ── O que esta tela NÃO faz, por decisão do founder (30-09-2026) ───────────\n//\n// Aceitar/recusar de verdade fala com a PlugNotas, e o `dfe-plugnotas-sync`\n// continua rodando no V1 por um período. Então aqui a manifestação é LEGÍVEL,\n// não acionável: a tela mostra a fila e o estado que veio da SEFAZ, e o botão\n// leva para a conciliação, que é o que a V2 assume agora.\n//\n// Um botão «Aceitar» que não fala com a SEFAZ seria pior que a ausência dele —\n// o operador acharia que cumpriu o prazo.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { ExternalLink, FileText, ShieldCheck } from 'lucide-react'\nimport { Button, Card, Hint, Skeleton, ListFilterBar } from '@fayz-ai/ui'\nimport { EmBreve } from './ComingSoon'\nimport { listInboxNotes } from '../data/inbox'\nimport type { InboxNote } from '../types'\n\nconst money = (v: number) => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(v || 0)\nconst day = (iso: string | null) => (iso ? iso.slice(0, 10).split('-').reverse().join('/') : '—')\n\n/** O estado que a SEFAZ devolveu, na palavra que o V1 grava. */\nconst MANIFEST_TONE: Record<string, string> = {\n confirmada: 'bg-success-soft text-success-soft-foreground',\n processando: 'bg-info-soft text-info-soft-foreground',\n erro: 'bg-destructive/10 text-destructive',\n}\n\ntype Tab = 'pendentes' | 'confirmadas' | 'erro' | 'todas'\n\nexport interface ManifestViewProps {\n onOpenNote: (noteId: string) => void\n}\n\nexport function ManifestView({ onOpenNote }: ManifestViewProps) {\n const [notes, setNotes] = useState<InboxNote[]>([])\n const [loading, setLoading] = useState(true)\n const [tab, setTab] = useState<Tab>('pendentes')\n\n const reload = useCallback(async () => {\n setLoading(true)\n try {\n setNotes(await listInboxNotes({ filter: 'all', limit: 300 }))\n } finally {\n setLoading(false)\n }\n }, [])\n\n useEffect(() => { void reload() }, [reload])\n\n const shown = useMemo(() => notes.filter((n) => {\n const status = n.manifestationStatus ?? ''\n if (tab === 'todas') return true\n if (tab === 'confirmadas') return status === 'confirmada'\n if (tab === 'erro') return status === 'erro'\n return status !== 'confirmada'\n }), [notes, tab])\n\n const pending = notes.filter((n) => (n.manifestationStatus ?? '') !== 'confirmada').length\n\n const filters = useMemo(() => ([{\n id: 'manifestacao',\n label: 'Manifestação',\n allLabel: 'Todas',\n value: tab === 'todas' ? undefined : tab,\n onChange: (v: string | undefined) => setTab((v as Tab) ?? 'todas'),\n options: [\n { value: 'pendentes', label: 'Pendentes' },\n { value: 'confirmadas', label: 'Confirmadas' },\n { value: 'erro', label: 'Com erro' },\n ],\n }]), [tab])\n\n return (\n <div className=\"space-y-4\">\n <Card className=\"p-4\">\n <div className=\"flex items-start gap-3\">\n <ShieldCheck className=\"mt-0.5 h-5 w-5 text-muted-foreground\" aria-hidden />\n <div>\n <p className=\"text-sm font-medium\">\n {pending} {pending === 1 ? 'nota aguardando' : 'notas aguardando'} manifestação à SEFAZ\n </p>\n <p className=\"text-xs text-muted-foreground\">\n Manifestar responde à SEFAZ e tem prazo. Dar entrada responde ao seu estoque e ao\n financeiro — são duas filas.\n </p>\n </div>\n </div>\n <Hint className=\"mt-3\">\n <span>\n A manifestação continua sendo feita no sistema antigo por enquanto. Aqui você lê a fila e\n o que a SEFAZ respondeu; a entrada no estoque e a conta a pagar já são feitas nesta tela\n nova.\n </span>\n </Hint>\n\n {/* As ações do topo do V1. Ficam VISÍVEIS e desligadas: quem não vê o botão\n conclui que a V2 não faz, e volta para o V1 para conferir a fila. */}\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <EmBreve label=\"Aceitar / Recusar\" o_que=\"Responder à SEFAZ — é obrigação com prazo. Hoje a manifestação é feita no sistema antigo\" />\n <EmBreve label=\"Puxar por chave\" o_que=\"Buscar uma NF-e específica pela chave de acesso de 44 dígitos\" />\n <EmBreve label=\"Sincronizar agora\" o_que=\"Pedir à SEFAZ o que chegou desde a última varredura\" />\n <EmBreve label=\"Resincronizar tudo\" o_que=\"Refazer a varredura inteira do período\" />\n <EmBreve label=\"Diagnosticar\" o_que=\"Por que uma nota não chegou: certificado, credencial ou cursor parado\" />\n </div>\n </Card>\n\n <ListFilterBar filters={filters} onClear={() => setTab('todas')} activeCount={tab === 'todas' ? 0 : 1} />\n\n {loading ? (\n <div className=\"space-y-2\">{[0, 1, 2].map((i) => <Skeleton key={i} className=\"h-12 w-full\" />)}</div>\n ) : shown.length === 0 ? (\n <Card className=\"p-10 text-center\">\n <FileText className=\"mx-auto h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mt-2 text-sm font-medium\">Nenhuma nota nesta fila</p>\n </Card>\n ) : (\n <Card className=\"overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead className=\"border-b bg-muted/40 text-xs text-muted-foreground\">\n <tr>\n <th className=\"px-3 py-2 text-left font-medium\">Emissão</th>\n <th className=\"px-3 py-2 text-left font-medium\">Nº</th>\n <th className=\"px-3 py-2 text-left font-medium\">Fornecedor</th>\n <th className=\"px-3 py-2 text-right font-medium\">Valor</th>\n <th className=\"px-3 py-2 text-right font-medium\">Parcelas</th>\n <th className=\"px-3 py-2 text-center font-medium\">Manifestação</th>\n <th className=\"px-3 py-2 text-right font-medium\">Ações</th>\n </tr>\n </thead>\n <tbody>\n {shown.map((note) => (\n <tr key={note.id} className=\"border-b last:border-0 hover:bg-muted/30\">\n <td className=\"px-3 py-2 tabular-nums text-muted-foreground\">{day(note.issueDate)}</td>\n <td className=\"px-3 py-2 tabular-nums font-medium\">{note.number}</td>\n <td className=\"px-3 py-2\">{note.supplierName || '—'}</td>\n <td className=\"px-3 py-2 text-right tabular-nums\">{money(note.total)}</td>\n <td className=\"px-3 py-2 text-right tabular-nums text-muted-foreground\">\n {note.instalmentCount}\n </td>\n <td className=\"px-3 py-2 text-center\">\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${\n MANIFEST_TONE[note.manifestationStatus ?? ''] ?? 'bg-muted text-muted-foreground'\n }`}>\n {note.manifestationStatus ?? 'não manifestada'}\n </span>\n </td>\n <td className=\"px-3 py-2\">\n <div className=\"flex items-center justify-end gap-1.5\">\n {/* Os dois do V1 que dependem do arquivo ter subido: o XML e\n o DANFE moram em `documents`, e `document_id` da nota\n ainda está nulo — os bytes atravessam pelo estágio de\n assets, que não rodou. */}\n <EmBreve label=\"XML\" o_que=\"Ver o XML bruto autorizado desta nota\" />\n <EmBreve label=\"PDF\" o_que=\"Abrir o DANFE desta nota\" />\n <Button size=\"sm\" variant=\"outline\" onClick={() => onOpenNote(note.id)}>\n Abrir conciliação\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </Button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </Card>\n )}\n </div>\n )\n}\n","// ---------------------------------------------------------------------------\n// A página de Entrada de Notas: lista, conciliação e manifesto numa moldura.\n// ---------------------------------------------------------------------------\n// As três vistas trocam por ESTADO LOCAL, não por rota. Trocar de rota remonta a\n// página e rebusca tudo — a lista pisca, a posição de rolagem se perde, e voltar\n// da conciliação recarrega 200 notas para mostrar a mesma coisa.\n//\n// O ENDEREÇO EMPILHA NA DESCIDA. `pushState` não dispara `hashchange`, então o\n// roteador do anfitrião continua sem remontar nada — mas a conciliação passa a\n// existir como um degrau no histórico. Com `replaceState` ela não existia, e o\n// «voltar» do cabeçalho (que anda pelo histórico quando a pessoa veio de outro\n// módulo) saltava a lista inteira e caía no Painel. Subir é desempilhar.\n// ---------------------------------------------------------------------------\nimport React, { useCallback, useEffect, useState } from 'react'\nimport { InboundNotesView } from './InboundNotesView'\nimport { NoteReconcileView } from './NoteReconcileView'\nimport { ManifestView } from './ManifestView'\n\ntype View =\n | { kind: 'list' }\n | { kind: 'manifest' }\n | { kind: 'note'; id: string }\n\nconst HASH_PREFIX = '#/inbound-notes'\n\nfunction viewFromLocation(): View {\n if (typeof window === 'undefined') return { kind: 'list' }\n const hash = window.location.hash\n const note = hash.match(/\\/inbound-notes\\/note\\/([0-9a-f-]{36})/i)\n if (note) return { kind: 'note', id: note[1] }\n if (/\\/inbound-notes\\/manifest/.test(hash)) return { kind: 'manifest' }\n return { kind: 'list' }\n}\n\nconst pathOf = (view: View) =>\n view.kind === 'note' ? `${HASH_PREFIX}/note/${view.id}`\n : view.kind === 'manifest' ? `${HASH_PREFIX}/manifest`\n : HASH_PREFIX\n\nexport interface InboundNotesPageProps {\n /** Onde o título a pagar vive no app anfitrião. Sem isto o botão não aparece. */\n payableRoute?: (invoiceId: string) => string\n}\n\n/** Marca as entradas que ESTA página empilhou, para só elas serem desempilhadas. */\nconst STACK_MARK = { inboundNotes: true }\n\nexport function InboundNotesPage({ payableRoute }: InboundNotesPageProps = {}) {\n const [view, setView] = useState<View>(viewFromLocation)\n\n const go = useCallback((next: View) => {\n setView(next)\n if (typeof window === 'undefined') return\n const path = pathOf(next)\n if (window.location.hash === path) return\n const empilhado = (window.history.state as { inboundNotes?: boolean } | null)?.inboundNotes\n if (next.kind === 'list' && empilhado) {\n // Desempilha de verdade: trocar a URL à mão deixaria a conciliação no\n // histórico e o «voltar» do navegador entraria nela outra vez.\n window.history.back()\n return\n }\n if (next.kind === 'list') window.history.replaceState(null, '', path)\n else window.history.pushState(STACK_MARK, '', path)\n }, [])\n\n // O «voltar» do navegador é um gesto legítimo aqui: quem entrou na conciliação\n // por um deep link espera sair dela com ele.\n useEffect(() => {\n if (typeof window === 'undefined') return\n const onPop = () => setView(viewFromLocation())\n window.addEventListener('popstate', onPop)\n window.addEventListener('hashchange', onPop)\n return () => {\n window.removeEventListener('popstate', onPop)\n window.removeEventListener('hashchange', onPop)\n }\n }, [])\n\n if (view.kind === 'note') {\n return (\n <NoteReconcileView\n noteId={view.id}\n onBack={() => go({ kind: 'list' })}\n onOpenInvoice={payableRoute\n ? (invoiceId) => { window.location.hash = payableRoute(invoiceId) }\n : undefined}\n />\n )\n }\n\n if (view.kind === 'manifest') {\n return (\n <div className=\"space-y-4\">\n <ManifestView onOpenNote={(id) => go({ kind: 'note', id })} />\n </div>\n )\n }\n\n return (\n <InboundNotesView\n onOpenNote={(id) => go({ kind: 'note', id })}\n onOpenManifest={() => go({ kind: 'manifest' })}\n />\n )\n}\n\n/**\n * O componente que o registro de rotas monta. Ele recebe as rotas sem prop, então\n * a configuração do host entra por fechamento — e a fábrica mora aqui, num `.tsx`,\n * para o manifesto continuar sendo TypeScript sem JSX.\n */\nexport function makeInboundNotesRoute(options: InboundNotesPageProps = {}): () => React.ReactElement {\n return function InboundNotesRoute() {\n return <InboundNotesPage {...options} />\n }\n}\n","import type { FinancialDataProvider } from '@fayz-ai/plugin-financial'\nimport type { PlugNotasFinancialProviderOptions } from '../types'\n\ntype FiscalDocument = NonNullable<Awaited<ReturnType<NonNullable<FinancialDataProvider['getNotaById']>>>>\n\nfunction fiscalReader(provider: FinancialDataProvider) {\n if (!provider.getNotaById) throw new Error('PlugNotas requires fiscal document reads from Financial.')\n return provider.getNotaById.bind(provider)\n}\n\nasync function committed(read: (id: string) => Promise<FiscalDocument | null>, id: string) {\n const document = await read(id)\n if (!document) throw new Error('Fiscal document was not found after the server operation.')\n return document\n}\n\nfunction resultError(result: { status: string; message?: string }, document: FiscalDocument, fallback: string) {\n if (result.status !== 'error') return\n throw new Error(result.message?.trim() || document.errorMessage?.trim() || fallback)\n}\n\nfunction cancellationPending(metadata: Record<string, unknown> | undefined): boolean {\n const provider = metadata?.plugnotas\n if (!provider || typeof provider !== 'object' || Array.isArray(provider)) return false\n return (provider as Record<string, unknown>).cancellationPending === true\n}\n\nfunction artifactUrl(value: unknown): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error('PlugNotas returned an invalid artifact URL.')\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n throw new Error('PlugNotas returned an invalid artifact URL.')\n }\n if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('PlugNotas returned an invalid artifact URL.')\n return parsed.toString()\n}\n\n/**\n * Decorates Financial without creating another fiscal ledger. The gateway only\n * requests server operations; every result returned to the UI is read back\n * from the server-committed `plg_financial_nfe` row.\n */\nexport function createPlugNotasFinancialProvider(\n options: PlugNotasFinancialProviderOptions,\n): FinancialDataProvider {\n const { base, gateway } = options\n\n const issueNota: NonNullable<FinancialDataProvider['issueNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.model !== 'nfce') throw new Error('PlugNotas currently authorizes NFC-e only.')\n if (!document.orderId?.trim()) throw new Error('PlugNotas NFC-e must be created from an order.')\n if (!['draft', 'error'].includes(document.status)) return document\n const result = await gateway.issue({ notaId: id, idempotencyKey: `nfce:${id}` })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not issue this NFC-e.')\n return saved\n }\n\n const refreshNota: NonNullable<FinancialDataProvider['refreshNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['processing', 'error'].includes(document.status) && !cancellationPending(document.metadata)) return document\n const result = await gateway.refresh({ notaId: id })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not refresh this NFC-e.')\n return saved\n }\n\n const cancelNota: NonNullable<FinancialDataProvider['cancelNota']> = async (id, reason) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.status !== 'issued') throw new Error('Only an issued NFC-e can be cancelled.')\n if (cancellationPending(document.metadata)) throw new Error('NFC-e cancellation is already in progress.')\n const normalized = reason?.trim() ?? ''\n if (normalized.length < 15 || normalized.length > 255) {\n throw new Error('Cancellation reason must contain between 15 and 255 characters.')\n }\n const result = await gateway.cancel({ notaId: id, reason: normalized })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not cancel this NFC-e.')\n return saved\n }\n\n const getNotaArtifactUrl: NonNullable<FinancialDataProvider['getNotaArtifactUrl']> = async (id, kind) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['issued', 'cancelled'].includes(document.status)) {\n throw new Error('Fiscal artifacts are available only after authorization.')\n }\n if (kind === 'cancellation_xml' && document.status !== 'cancelled') {\n throw new Error('Cancellation XML is available only after cancellation.')\n }\n return artifactUrl((await gateway.artifact({ notaId: id, kind })).url)\n }\n\n return new Proxy(base, {\n get(target, property, receiver) {\n if (property === 'issueNota') return issueNota\n if (property === 'refreshNota') return refreshNota\n if (property === 'cancelNota') return cancelNota\n if (property === 'getNotaArtifactUrl') return getNotaArtifactUrl\n return Reflect.get(target, property, receiver)\n },\n })\n}\n","// ---------------------------------------------------------------------------\n// As telas que ainda não existem, com o que se sabe sobre cada uma.\n// ---------------------------------------------------------------------------\n// Tudo aqui saiu de medição no V1 de produção da Artorius (tenant 12) entre\n// 29 e 30/09/2026 — o rastro de auditoria da LAISSA FLOR, que é quem lança. Os\n// números não são estimativa: são quantas vezes ela fez aquilo.\n// ---------------------------------------------------------------------------\nimport React from 'react'\nimport { ComingSoon } from './ComingSoon'\n\n/**\n * Grupos Fiscais — a 5ª tela do grupo no V1. Na V2 o grupo fiscal já existe como\n * CADASTRO (`fiscalRegistries`), só não tem porta aqui dentro.\n */\nexport function TaxGroupsView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Grupos Fiscais\"\n summary=\"Perfis tributários reutilizáveis — CFOP, CSOSN/CST, PIS, COFINS, ICMS — que os produtos usam na emissão.\"\n v1Path=\"Estoque → Notas Fiscais → Grupos Fiscais\"\n measured=\"Vazio no V1 da Artorius («Nenhum grupo fiscal cadastrado»), coerente com eles não emitirem nota. O Pertinho do Céu e o Espaço Facial têm 11 entre os dois.\"\n missing={[\n 'Trazer o cadastro para dentro do grupo: a tabela plg_fiscalbr_tax_groups já existe e já recebeu os 11 grupos do V1',\n 'Hoje ele só aparece na lista genérica de cadastros, longe de onde a nota é usada',\n 'Só faz sentido junto com Notas Emitidas — grupo fiscal é insumo de emissão',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n/** Notas Emitidas — no V1 FUNCIONA, e é o gap maior dos dois. */\nexport function IssuedNotesView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Notas Emitidas\"\n summary=\"As NF-e, NFS-e e NFC-e que a casa emitiu, com o estado de cada uma na SEFAZ — autorizada, processando, rejeitada ou cancelada — e a comanda ou fatura que deu origem a ela.\"\n v1Path=\"Estoque → Notas Fiscais → Notas Emitidas\"\n measured=\"A Artorius não emite nota hoje: em 80 documentos recebidos, zero emitidos. Quem emite é o Pertinho do Céu e o Espaço Facial.\"\n missing={[\n 'Ligar o emissor da PlugNotas a este CNPJ (o certificado A1 já está lá desde maio; falta a credencial chegar neste ambiente)',\n 'A lista com o estado na SEFAZ e o rastro de tentativas — as tabelas já existem (plg_fiscalbr_nfce_jobs, _events)',\n 'Abrir o XML autorizado e o DANFE de cada nota',\n 'Cancelar uma nota emitida, com justificativa',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n/** Notas Devolvidas — no V1 é STUB, e a tela diz isso. */\nexport function ReturnedNotesView({ onBack }: { onBack?: () => void } = {}) {\n return (\n <ComingSoon\n title=\"Notas Devolvidas\"\n summary=\"As notas fiscais de devolução: o que voltou para o fornecedor, e o que isso desfaz no estoque e na conta a pagar.\"\n v1Path=\"Estoque → Notas Fiscais → Notas Devolvidas\"\n v1AlsoMissing\n missing={[\n 'Decidir o gesto: devolver a nota INTEIRA ou só algumas linhas dela',\n 'A devolução ESTORNA o estoque que a entrada criou — e o movimento de estorno já existe no V2 (reverses_movement_id)',\n 'E abate o título a pagar, ou gera um crédito com o fornecedor. É decisão de produto, não de código',\n 'Emitir a NF-e de devolução exige emissor ligado — mesma dependência de Notas Emitidas',\n ]}\n onBack={onBack}\n backTo=\"Notas Fiscais\"\n />\n )\n}\n\n","// ---------------------------------------------------------------------------\n// O grupo «Notas Fiscais», pronto para o Estoque montar.\n// ---------------------------------------------------------------------------\n// O V1 agrupa CINCO telas sob «Notas Fiscais», dentro do Estoque:\n//\n// Manifesto de Notas funciona (118 pendentes lá)\n// Entrada de Notas funciona — é o grosso do trabalho\n// Grupos Fiscais funciona, vazio (é cadastro, e no V2 entra como registry)\n// Notas Emitidas funciona no V1, falta aqui\n// Notas Devolvidas STUB no V1 também\n//\n// Aqui vão as quatro que são TELA. O app chama isto em\n// `createInventoryPlugin({ extraViews: [inboundNotesInventoryView()] })`, e o\n// operador acha tudo onde sempre achou: dentro do Estoque.\n//\n// As que não funcionam não são escondidas. Quem não vê a função conclui que o V2\n// não a tem — e descobrimos isso pelo suporte, não pelo plano.\n// ---------------------------------------------------------------------------\nimport React from 'react'\nimport { InboundNotesPage, type InboundNotesPageProps } from './InboundNotesPage'\nimport { IssuedNotesView, ReturnedNotesView, TaxGroupsView } from './GapScreens'\n\nexport function inboundNotesInventoryView(options: InboundNotesPageProps = {}) {\n return {\n id: 'inbound-notes',\n label: 'Notas Fiscais',\n icon: 'FileText',\n render: () => <InboundNotesPage {...options} />,\n // A ordem é a do V1: Grupos Fiscais vem antes das duas de emissão, que é\n // onde ele é usado.\n //\n // Bonificação NÃO é aba. Ela chegou aqui por engano meu: no V1 não existe\n // esse menu — a bonificação é uma NATUREZA DE OPERAÇÃO que vem escrita na\n // nota (57 delas, em 11 grafias), e o que ela muda é o comportamento da\n // entrada: a mercadoria soma ao estoque e NÃO abre conta a pagar. O aviso\n // continua onde serve, na conciliação da nota. Uma tela vazia para um\n // comportamento é um menu que promete o que não vai entregar.\n children: [\n { id: 'tax-groups', label: 'Grupos Fiscais', render: () => <TaxGroupsView /> },\n { id: 'issued-notes', label: 'Notas Emitidas', render: () => <IssuedNotesView /> },\n { id: 'returned-notes', label: 'Notas Devolvidas', render: () => <ReturnedNotesView /> },\n ],\n }\n}\n","import { definePlugin, type PluginManifest } from '@fayz-ai/core'\nimport { createPlugNotasConnector, type CreatePlugNotasConnectorOptions } from './connectors/plugnotas'\nimport { MIGRATIONS } from './migrations'\nimport { fiscalRegistries } from './data/registries'\nimport { makeInboundNotesRoute } from './views/InboundNotesPage'\n\nexport * from './connectors/plugnotas'\nexport * from './lib/financial-provider'\nexport * from './types'\nexport * from './lib/nfe-xml'\nexport * from './data/inbox'\nexport { InboundNotesPage } from './views/InboundNotesPage'\nexport { InboundNotesView } from './views/InboundNotesView'\nexport { NoteReconcileView } from './views/NoteReconcileView'\nexport { ManifestView } from './views/ManifestView'\nexport { ComingSoon, EmBreve } from './views/ComingSoon'\nexport { IssuedNotesView, ReturnedNotesView, TaxGroupsView } from './views/GapScreens'\n/**\n * O grupo «Notas Fiscais» como o V1 o desenha: cinco telas sob uma aba. Duas\n * funcionam, três anunciam o que falta. O app passa isto para\n * `createInventoryPlugin({ extraViews })` e o Estoque desenha.\n */\nexport { inboundNotesInventoryView } from './views/inventoryView'\n\nexport interface CreatePlugNotasPluginOptions extends CreatePlugNotasConnectorOptions {\n /** Onde a linha de Entrada de Notas entra no rail. Default: `main`, posição 5 (depois do estoque). */\n navSection?: 'main' | 'secondary' | 'settings'\n navPosition?: number\n /**\n * Onde o título a pagar vive no app anfitrião, para o botão «Abrir a conta a\n * pagar» depois de aceitar. Sem isto o botão não aparece — um botão que leva a\n * lugar nenhum é pior que a ausência dele.\n */\n payableRoute?: (invoiceId: string) => string\n}\n\n/**\n * Fiscal Brasil is an addon: Financial owns the fiscal document, while this\n * package owns the provider connection and its asynchronous delivery trail.\n */\nexport function createPlugNotasPlugin(options: CreatePlugNotasPluginOptions = {}): PluginManifest {\n return definePlugin({\n id: 'fiscal-br',\n name: 'Fiscal Brasil',\n icon: 'ReceiptText',\n version: '0.1.0',\n apiVersion: 1,\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['financial'],\n // SEM linha no rail, de propósito.\n //\n // Entrada de Notas é assunto de ESTOQUE, não assunto do menu: no V1 o caminho\n // é `Estoque → Notas Fiscais → Entrada de Notas`. Montei como linha solta na\n // primeira tentativa e estava errado — quem vem do V1 procura dentro do\n // Estoque e não acha. O app entrega a tela ao inventário por\n // `createInventoryPlugin({ extraViews })`, e ela aparece como aba irmã de\n // Produtos, Movimentações e Contagens.\n //\n // A rota própria FICA: ela é o deep link (`#/inbound-notes`), e é por onde o\n // agente e um link de e-mail chegam sem passar pela faixa de abas.\n navigation: [],\n routes: [\n {\n path: '/inbound-notes',\n // O registro de rotas monta componentes sem prop. A opção do host entra\n // por fechamento, e a fábrica mora no `.tsx` para este manifesto seguir\n // sendo TypeScript sem JSX.\n component: makeInboundNotesRoute({ payableRoute: options.payableRoute }),\n permission: { feature: 'financial', action: 'read' as const },\n },\n ],\n // O grupo fiscal é CADASTRO, e por isso entra como registry e não como\n // rota própria: ele aparece onde os outros cadastros do produto aparecem.\n registries: fiscalRegistries,\n connectors: [createPlugNotasConnector(options)],\n functions: [{\n slug: 'plugnotas-bridge',\n ingress: 'none',\n verifyJwt: false,\n secrets: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n 'SUPABASE_URL',\n 'SUPABASE_ANON_KEY',\n 'SUPABASE_SERVICE_ROLE_KEY'\n ],\n grants: [\n 'plugnotas_register_emitter',\n 'plugnotas_disconnect_emitter',\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_prepare_nfce_cancel',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_get_artifact_locator',\n 'plugnotas_claim_nfce_recovery',\n 'plugnotas_record_nfce_attempt'\n ],\n }],\n migrations: MIGRATIONS.map((entry) => ({\n id: `fiscal-br-${entry.id}`,\n version: '1.0.0',\n sql: entry.sql,\n description: 'Durable PlugNotas delivery, recovery, webhook and emitter-registration boundary.',\n })),\n diagnostics: [{\n id: 'plugnotas-nfce-ready',\n description: 'NFC-e requires the shared connection, order, item and financial fiscal-document contracts.',\n requires: {\n tables: [\n 'connections',\n 'orders',\n 'items',\n 'plg_financial_nfe',\n 'plg_fiscalbr_nfce_jobs',\n 'plg_fiscalbr_nfce_events',\n 'plg_fiscalbr_webhook_receipts',\n ],\n rpcs: [\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_claim_nfce_recovery',\n ],\n env: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n ],\n },\n level: 'error',\n }],\n })\n}\n"]}
|