@fayz-ai/plugin-inventory 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/mock.d.ts.map +1 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/tables.d.ts +2 -0
- package/dist/data/tables.d.ts.map +1 -1
- package/dist/data/types.d.ts +30 -1
- package/dist/data/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5024 -3706
- package/dist/index.js.map +1 -1
- package/dist/lib/movement-vocabulary.d.ts.map +1 -1
- package/dist/lib/onboarding.d.ts +11 -0
- package/dist/lib/onboarding.d.ts.map +1 -0
- package/dist/lib/setup-guides.d.ts +3 -0
- package/dist/lib/setup-guides.d.ts.map +1 -0
- package/dist/lib/stock-count.d.ts +4 -1
- package/dist/lib/stock-count.d.ts.map +1 -1
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +3 -25
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/store.d.ts +16 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/types.d.ts +87 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/views/InventoryPage.d.ts.map +1 -1
- package/dist/views/MovementHistoryView.d.ts.map +1 -1
- package/dist/views/ProductCrudForm.d.ts.map +1 -1
- package/dist/views/ProductListView.d.ts.map +1 -1
- package/dist/views/ProductStockTab.d.ts.map +1 -1
- package/dist/views/RecipeDetailView.d.ts.map +1 -1
- package/dist/views/RecipesView.d.ts.map +1 -1
- package/dist/views/StockCountsView.d.ts.map +1 -1
- package/dist/views/StockMovementView.d.ts.map +1 -1
- package/dist/views/UsageAuditView.d.ts +3 -0
- package/dist/views/UsageAuditView.d.ts.map +1 -0
- package/package.json +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/views/DashboardView.tsx","../src/data/tables.ts","../src/lib/movement-vocabulary.ts","../src/views/ProductStockTab.tsx","../src/views/productEntity.tsx","../src/views/ProductListView.tsx","../src/views/ProductCrudForm.tsx","../src/views/ProductDetailView.tsx","../src/views/StockMovementView.tsx","../src/views/MovementHistoryView.tsx","../src/views/StockCountsView.tsx","../src/views/StockCountFormView.tsx","../src/lib/stock-count.ts","../src/views/StockCountSessionView.tsx","../src/lib/recipe-cost.ts","../src/lib/agent-tools.ts","../src/views/RecipesView.tsx","../src/views/RecipeFormView.tsx","../src/components/RecipeGapsPanel.tsx","../src/views/RecipeDetailView.tsx","../src/components/InventoryGeneralSettings.tsx","../src/components/InventoryOnboarding.tsx","../src/views/InventoryPage.tsx","../src/views/dashboardWidgets.tsx","../src/data/mock.ts","../src/data/reference-data.ts","../src/data/supabase.ts","../src/store.ts","../src/data/registries.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/migrations/index.ts","../src/index.ts"],"names":["jsx","t","jsxs","useTranslation","useState","useMemo","useEffect","useCallback","toast","React","SubpageHeader","MOVEMENT_TYPES","Package","ArrowDownRight","ArrowUpRight","RefreshCw","ArrowRightLeft","Trash2","Button","CrudListView","Fragment","ConfirmDialog","useRef","useLimitGuard","invalidateLimit","name","SearchSelect","Plus","AlertTriangle","DetailSkeleton","DataTable","Check","ctx","nextId","applyPositionDelta","createStore","PluginSettingsPanel"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;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;AA6OjC,IAAM,0BAAA,GAA6B,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,CAAA;AA+TnC,IAAM,sBAAA,GAAyB,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,CAAA;AAgD/B,IAAM,qCAAA,GAAwC,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;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;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;AAqlB9C,IAAM,6BAAA,GAAgC,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,CAAA;AA8PtC,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAsUpD,IAAM,4BAAA,GAA+B,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;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAyrBrC,IAAM,uCAAA,GAA0C,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,CAAA;AA4FhD,IAAM,wCAAA,GAA2C,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,CAAA;AAqEjD,IAAM,4BAAA,GAA+B,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,CAAA;AAyErC,IAAM,yCAAA,GAA4C,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,CAAA;AA0ClD,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;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;AAyHvD,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,CAAA;AA8HxD,IAAM,gDAAA,GAAmD,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,CAAA;AAgDzD,IAAM,iDAAA,GAAoD,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,CAAA;AAkJ1D,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;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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 { createPluginContext, formatCurrency, type CurrencyConfig } from '@fayz-ai/admin'\nimport type { InventoryPluginLabels } from './index'\nimport type { InventoryDataProvider } from './data/types'\nimport type { InventoryUIState } from './store'\n\nexport interface InventoryModules {\n /** Product catalogue screens. Off when the host registers products elsewhere. */\n products: boolean\n recipes: boolean\n stockLocations: boolean\n batchTracking: boolean\n}\n\nexport type InventoryCurrency = CurrencyConfig\n\nexport interface ProductTypeOption {\n value: string\n label: string\n}\n\nexport interface LocationOption {\n id: string\n name: string\n isHQ?: boolean\n}\n\nexport interface ResolvedInventoryConfig {\n modules: InventoryModules\n labels: InventoryPluginLabels\n currency: InventoryCurrency\n productTypes: ProductTypeOption[]\n locations: LocationOption[]\n}\n\nconst ctx = createPluginContext<ResolvedInventoryConfig, InventoryDataProvider, InventoryUIState>('InventoryPage')\n\nexport const InventoryContextProvider = ctx.ContextProvider\nexport const useInventoryConfig = ctx.useConfig\nexport const useInventoryProvider = ctx.useProvider\nexport const useInventoryStore = ctx.useStore\n\nexport { formatCurrency }\n","import React from 'react'\nimport { DashboardCanvas } from '@fayz-ai/ui'\n\n/**\n * Inventory overview. KPIs and the activity panel are registered dashboard\n * widgets (see ./dashboardWidgets), rendered through the shared DashboardCanvas;\n * the stock-value KPI also surfaces on the global app home.\n */\nexport function DashboardView() {\n return <DashboardCanvas surface=\"plugin-home\" domain=\"inventory\" showHeader={false} className=\"space-y-6\" />\n}\n","// Central physical-table-name registry for plugin-inventory.\nexport const T = {\n stockLocations: 'plg_inventory_stock_locations',\n stockMovements: 'plg_inventory_stock_movements',\n stockPositions: 'plg_inventory_stock_positions',\n recipes: 'plg_inventory_recipes',\n recipeIngredients: 'plg_inventory_recipe_ingredients',\n measurementUnits: 'plg_inventory_measurement_units',\n productCategories: 'plg_inventory_product_categories',\n productDetails: 'plg_inventory_product_details',\n recipeGroups: 'plg_inventory_recipe_groups',\n countSessions: 'plg_inventory_count_sessions',\n countItems: 'plg_inventory_count_items',\n} as const\n\n/** Slot key of plg_inventory_stock_positions — matches uq_..._slot (006). */\nexport const STOCK_POSITION_SLOT = 'tenant_id,product_id,stock_location_id,batch_number,expiration_date'\n","import type { MovementType } from '../types'\n\n/**\n * The one list of stock movement types.\n *\n * This used to be spelled out in three places — the MovementType union, the\n * form's picker and the history's icon/colour maps — which is three chances to\n * disagree. Importers make it four. Everything reads from here.\n */\nexport interface MovementTypeSpec {\n value: MovementType\n /** i18n key under the plugin's `inventory.movementType` namespace. */\n labelKey: string\n /** lucide icon name, resolved by the host's icon map. */\n icon: string\n /** Direction on stock: what the quantity does to the on-hand total. */\n effect: 'increase' | 'decrease' | 'set' | 'move'\n}\n\nexport const MOVEMENT_TYPES: readonly MovementTypeSpec[] = [\n { value: 'entry', labelKey: 'inventory.movementType.entry', icon: 'ArrowDownToLine', effect: 'increase' },\n { value: 'exit', labelKey: 'inventory.movementType.exit', icon: 'ArrowUpFromLine', effect: 'decrease' },\n { value: 'adjustment', labelKey: 'inventory.movementType.adjustment', icon: 'Scale', effect: 'set' },\n { value: 'transfer', labelKey: 'inventory.movementType.transfer', icon: 'ArrowLeftRight', effect: 'move' },\n { value: 'loss', labelKey: 'inventory.movementType.loss', icon: 'TriangleAlert', effect: 'decrease' },\n] as const\n\nexport const MOVEMENT_TYPE_VALUES: readonly MovementType[] = MOVEMENT_TYPES.map((m) => m.value)\n\nexport function movementTypeSpec(value: string): MovementTypeSpec | undefined {\n return MOVEMENT_TYPES.find((m) => m.value === value)\n}\n\n/**\n * Portuguese movement vocabulary used by pre-SDK apps (beautyplace and its\n * descendants). Lives next to the canonical list so a data import cannot drift\n * from what the UI can render — that is the whole reason it is here and not in\n * the importer.\n */\nexport const LEGACY_PT_MOVEMENT_TYPE: Readonly<Record<string, MovementType>> = {\n entrada: 'entry',\n saida: 'exit',\n 'saída': 'exit',\n ajuste: 'adjustment',\n transferencia: 'transfer',\n 'transferência': 'transfer',\n perda: 'loss',\n} as const\n\n/** Normalise any known spelling to a MovementType; undefined when unrecognised. */\nexport function normalizeMovementType(raw: string): MovementType | undefined {\n const v = raw.trim().toLowerCase()\n if ((MOVEMENT_TYPE_VALUES as readonly string[]).includes(v)) return v as MovementType\n return LEGACY_PT_MOVEMENT_TYPE[v]\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Undo2 } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button, ConfirmDialog, DataTable, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { Product, StockMovement, StockPosition } from '../types'\nimport { movementTypeSpec } from '../lib/movement-vocabulary'\n\nfunction TableSkeleton() {\n return (\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-3.5 rounded bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )\n}\n\nfunction EmptyLine({ message }: { message: string }) {\n return (\n <div className=\"rounded-card border p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{message}</p>\n </div>\n )\n}\n\n/**\n * \"How much costela do I have, where, and where did it go\" — answered on the\n * product itself instead of by filtering the global ledger.\n */\nexport function ProductStockTab({ item, onChanged }: { item: Product; onChanged?: () => void }) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [positions, setPositions] = useState<StockPosition[]>([])\n const [movements, setMovements] = useState<StockMovement[]>([])\n const [loading, setLoading] = useState(true)\n const [confirming, setConfirming] = useState(false)\n const [undoing, setUndoing] = useState(false)\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n const [pos, history] = await Promise.all([\n provider.getPositions(item.id),\n provider.getMovements({ productId: item.id, pageSize: 100 }),\n ])\n setPositions(pos)\n setMovements(history.data)\n } finally {\n setLoading(false)\n }\n }, [item.id, provider])\n\n useEffect(() => { void load() }, [load])\n\n // Ordered by when it was RECORDED, not by movement date: undoing means taking\n // back the last thing someone typed, which a backdated entry would hide.\n const ordered = useMemo(\n () => [...movements].sort((a, b) => (b.createdAt ?? b.movementDate).localeCompare(a.createdAt ?? a.movementDate)),\n [movements],\n )\n const lastMovement = ordered[0]\n const onHand = useMemo(() => positions.reduce((sum, p) => sum + (p.quantity ?? 0), 0), [positions])\n\n const movementLabel = (m: StockMovement) => {\n const spec = movementTypeSpec(m.movementType)\n return spec ? t(spec.labelKey) : m.movementType\n }\n\n async function handleUndo() {\n if (!lastMovement) return\n setUndoing(true)\n try {\n await provider.reverseMovement(lastMovement.id)\n toast.success(t('inventory.productDetail.undone'))\n await load()\n onChanged?.()\n } catch (err: any) {\n toast.error(t('inventory.productDetail.undoFailed'), { description: err?.message })\n } finally {\n setUndoing(false)\n setConfirming(false)\n }\n }\n\n const positionColumns: ColumnDef<StockPosition, any>[] = useMemo(() => [\n {\n accessorKey: 'stockLocationName', header: t('inventory.stock.locationLabel'),\n cell: ({ getValue }: any) => <span className=\"font-medium\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'batchNumber', header: t('inventory.stock.batchNumber'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'expirationDate', header: t('inventory.stock.expirationDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'unitCost', header: () => <span className=\"block text-right\">{t('inventory.stock.unitCostLabel')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right text-muted-foreground\">{formatCurrency(Number(getValue()) || 0, currency)}</span>,\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.stock.quantityLabel')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right font-medium tabular-nums\">{getValue() as number}</span>,\n },\n {\n id: 'total', header: () => <span className=\"block text-right\">{t('inventory.stock.totalCost')}</span>,\n cell: ({ row }: any) => (\n <span className=\"block text-right tabular-nums\">\n {formatCurrency((row.original.quantity ?? 0) * (row.original.unitCost ?? 0), currency)}\n </span>\n ),\n },\n ], [currency, t])\n\n const movementColumns: ColumnDef<StockMovement, any>[] = useMemo(() => [\n {\n accessorKey: 'movementDate', header: t('inventory.history.columnDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{getValue() as string}</span>,\n },\n {\n accessorKey: 'movementType', header: t('inventory.history.columnType'),\n cell: ({ row }: any) => <span className=\"text-xs\">{movementLabel(row.original)}</span>,\n },\n {\n accessorKey: 'stockLocationName', header: t('inventory.history.columnLocation'),\n cell: ({ row }: any) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.stockLocationName ?? '—'}\n {row.original.movementType === 'transfer' && row.original.destinationLocationName && (\n <span> → {row.original.destinationLocationName}</span>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.history.columnQty')}</span>,\n cell: ({ row }: any) => (\n <span className=\"block text-right tabular-nums\">\n {row.original.movementType === 'entry' ? '+' : '-'}{row.original.quantity}\n </span>\n ),\n },\n {\n accessorKey: 'totalCost', header: () => <span className=\"block text-right\">{t('inventory.history.columnTotal')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right text-muted-foreground\">{formatCurrency(Number(getValue()) || 0, currency)}</span>,\n },\n ], [currency, t])\n\n if (loading) return <TableSkeleton />\n\n return (\n <div className=\"space-y-6\">\n <section className=\"space-y-2\">\n <div className=\"flex items-baseline justify-between\">\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.productDetail.positionsTitle')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.productDetail.onHand')} <span className=\"font-medium text-foreground tabular-nums\">{onHand}</span>\n </p>\n </div>\n {positions.length === 0\n ? <EmptyLine message={t('inventory.productDetail.noPositions')} />\n : <DataTable columns={positionColumns} data={positions} variant=\"card\" />}\n </section>\n\n <section className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.productDetail.historyTitle')}</h3>\n {lastMovement && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => setConfirming(true)}\n >\n <Undo2 className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('inventory.productDetail.undoLast')}\n </Button>\n )}\n </div>\n {ordered.length === 0\n ? <EmptyLine message={t('inventory.history.noMovements')} />\n : <DataTable columns={movementColumns} data={ordered} variant=\"card\" />}\n </section>\n\n <ConfirmDialog\n open={confirming}\n variant=\"destructive\"\n title={t('inventory.productDetail.undoTitle')}\n description={lastMovement ? t('inventory.productDetail.undoDescription', {\n type: movementLabel(lastMovement),\n quantity: String(lastMovement.quantity),\n date: lastMovement.movementDate,\n }) : undefined}\n confirmLabel={t('inventory.productDetail.undoConfirm')}\n cancelLabel={t('inventory.productForm.cancel')}\n loading={undoing}\n onConfirm={() => void handleUndo()}\n onCancel={() => setConfirming(false)}\n />\n </div>\n )\n}\n","import React from 'react'\nimport type { EntityDef, EntityImageConfig, FieldDef } from '@fayz-ai/core'\nimport { formatCurrency, type InventoryCurrency, type ProductTypeOption } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport { T } from '../data/tables'\nimport { ProductStockTab } from './ProductStockTab'\n\n// ---------------------------------------------------------------------------\n// The single source of truth for the Product entity — drives BOTH the generic\n// list (CrudListView columns + facet) and the generic form (CrudFormPage\n// sections). Persistence stays in the inventory provider/store; this only\n// describes fields, columns and layout.\n// ---------------------------------------------------------------------------\n\nconst TYPE_DESCRIPTION_KEYS: Record<string, string> = {\n ingredient: 'inventory.productForm.typeIngredient',\n sale: 'inventory.productForm.typeSale',\n intermediate: 'inventory.productForm.typeIntermediate',\n asset: 'inventory.productForm.typeAsset',\n}\n\ntype T = (key: string, params?: Record<string, string | number>) => string\n\nfunction productImage(provider: InventoryDataProvider): EntityImageConfig {\n return {\n get: (row) => row.imageUrl,\n upload: async (file, row) => {\n if (!row.id) throw new Error('Salve o produto antes de enviar a imagem.')\n if (!provider.uploadProductImage) throw new Error('Envio de imagens indisponível neste ambiente.')\n return provider.uploadProductImage(row.id, file)\n },\n accept: 'image/jpeg,image/png,image/webp,image/heic,image/heif',\n // CrudFormPage keeps this File only in form state. ProductCrudForm consumes\n // it after createProduct returns the new id; it never reaches PostgREST.\n draftField: '_imageFile',\n }\n}\n\nexport function buildProductEntity(\n t: T,\n productTypes: ProductTypeOption[],\n currency: InventoryCurrency,\n /** Called by the Stock tab after it changes stock, so the page can refetch. */\n onStockChanged?: () => void,\n /** Enables the real media slot; list-only consumers may omit it. */\n provider?: InventoryDataProvider,\n): EntityDef {\n const typeOptions = productTypes.map((pt) => ({\n label: pt.label,\n value: pt.value,\n description: TYPE_DESCRIPTION_KEYS[pt.value] ? t(TYPE_DESCRIPTION_KEYS[pt.value]) : undefined,\n }))\n const typeLabel = (v: unknown) => productTypes.find((p) => p.value === v)?.label ?? String(v ?? '')\n\n // Field order is chosen so the table columns come out as\n // Product · Type · Stock · Cost · Value while the form groups stay correct.\n const fields: FieldDef[] = [\n // — General Information (form) + Product column (table) —\n {\n key: 'name', label: t('inventory.productForm.name'), type: 'text', required: true,\n group: 'general', placeholder: t('inventory.productForm.namePlaceholder'),\n searchable: true, showInTable: true, sortable: true,\n renderCell: (_v, row: any) => (\n <div>\n <div className=\"flex items-center gap-1.5\">\n <p className={`font-medium ${row.isActive === false ? 'text-muted-foreground' : ''}`}>{row.name}</p>\n {/* Fora de linha tem de SER visível: sem esta marca, desativar um\n produto não mudava nada na tela e a ação parecia não ter feito\n nada. */}\n {row.isActive === false && (\n <span className=\"inline-flex items-center rounded-full bg-muted px-1.5 py-0.5 text-[9px] font-medium text-muted-foreground\">\n {t('inventory.productList.inactive')}\n </span>\n )}\n </div>\n {row.sku && <p className=\"text-xs text-muted-foreground\">{row.sku}</p>}\n </div>\n ),\n },\n { key: 'brand', label: t('inventory.productForm.brand'), type: 'text', group: 'general', placeholder: t('inventory.productForm.brandPlaceholder'), showInTable: false },\n { key: 'sku', label: t('inventory.productForm.sku'), type: 'text', group: 'general', placeholder: t('inventory.productForm.skuPlaceholder'), searchable: true, showInTable: false },\n { key: 'barcode', label: t('inventory.productForm.barcode'), type: 'text', group: 'general', placeholder: t('inventory.productForm.barcodePlaceholder'), searchable: true, showInTable: false },\n { key: 'description', label: t('inventory.productForm.description'), type: 'textarea', group: 'general', span: 2, placeholder: t('inventory.productForm.descriptionPlaceholder'), showInTable: false },\n\n // — Classification (form: segmented) + Type column (table: badge) —\n {\n key: 'productType', label: t('inventory.productForm.classification'), type: 'segmented',\n group: 'classification', span: 2, options: typeOptions,\n showInTable: true, sortable: false,\n renderCell: (v) => (\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium bg-muted text-muted-foreground\">\n {typeLabel(v)}\n </span>\n ),\n },\n\n // — Stock column (list only) — placed before Cost for the desired column order\n {\n key: 'currentQuantity', label: t('inventory.productList.stock'), type: 'number',\n showInForm: false, showInTable: true, sortable: true,\n renderCell: (_v, row: any) => (\n <span className={`text-right block ${row.currentQuantity <= row.minQuantity ? 'text-destructive font-medium' : ''}`}>\n {row.currentQuantity}\n </span>\n ),\n },\n\n // — Pricing (form) + Cost column (table) —\n {\n key: 'costPrice', label: t('inventory.productForm.costPrice'), type: 'currency',\n group: 'pricing', currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n showInTable: true, sortable: false,\n renderCell: (v) => <span className=\"text-right block text-muted-foreground\">{formatCurrency(Number(v) || 0, currency)}</span>,\n },\n\n // — Value column (list only): stock × cost —\n {\n key: 'value', label: t('inventory.productList.value'), type: 'number',\n showInForm: false, showInTable: true, sortable: false,\n renderCell: (_v, row: any) => (\n <span className=\"text-right block font-medium\">{formatCurrency((row.currentQuantity || 0) * (row.costPrice || 0), currency)}</span>\n ),\n },\n\n {\n key: 'salePrice', label: t('inventory.productForm.salePrice'), type: 'currency', group: 'pricing',\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n showInTable: false,\n // Ingredients and intermediate preparations are inputs, not things sold\n // directly to the customer. If it is sold, it belongs to the menu-item\n // classification and gets the commercial fields there.\n visibleWhen: (vals) => vals.productType === 'sale',\n },\n {\n key: 'margin', label: t('inventory.productForm.margin'), type: 'computed', group: 'pricing', showInTable: false,\n visibleWhen: (vals) => vals.productType === 'sale',\n compute: (vals) => {\n const cost = Number(vals.costPrice) || 0\n const sale = Number(vals.salePrice) || 0\n if (sale <= 0 || cost <= 0) return null\n const m = ((sale - cost) / cost) * 100\n return { display: `${m.toFixed(1)}%`, tone: m >= 0 ? 'positive' : 'negative' }\n },\n },\n\n // — Stock Levels (form only) —\n { key: 'minQuantity', label: t('inventory.productForm.minQuantity'), type: 'number', group: 'stock', min: 0, placeholder: '0', hint: t('inventory.productForm.minQuantityHint'), showInTable: false },\n { key: 'maxQuantity', label: t('inventory.productForm.maxQuantity'), type: 'number', group: 'stock', min: 0, placeholder: t('inventory.productForm.optional'), hint: t('inventory.productForm.maxQuantityHint'), showInTable: false },\n\n // — Organisation (form only) — the four links that used to be accepted by\n // CreateProductInput and then silently dropped; they persist in\n // plg_inventory_product_details since migration 005.\n {\n key: 'categoryId', label: t('inventory.productForm.category'), type: 'relation', group: 'organization',\n relation: { table: T.productCategories, labelField: 'name' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'measurementUnitId', label: t('inventory.productForm.measurementUnit'), type: 'relation', group: 'organization',\n relation: { table: T.measurementUnits, labelField: 'abbreviation' },\n hint: t('inventory.productForm.measurementUnitHint'),\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'supplierId', label: t('inventory.productForm.supplier'), type: 'relation', group: 'organization',\n relation: { table: 'people', labelField: 'name', filter: { kind: 'supplier' } },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'defaultLocationId', label: t('inventory.productForm.defaultLocation'), type: 'relation', group: 'organization',\n relation: { table: T.stockLocations, labelField: 'name' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n ]\n\n return {\n name: t('inventory.stock.product'),\n namePlural: t('inventory.nav.products'),\n icon: 'Package',\n displayField: 'name',\n image: provider?.uploadProductImage ? productImage(provider) : undefined,\n fields,\n fieldGroups: [\n { id: 'general', label: t('inventory.productForm.generalInfo'), columns: 2, imageSlot: true },\n { id: 'classification', label: t('inventory.productForm.classification'), description: t('inventory.productForm.classificationDesc'), columns: 1 },\n { id: 'pricing', label: t('inventory.productForm.pricing'), columns: 3 },\n { id: 'stock', label: t('inventory.productForm.stockLevels'), description: t('inventory.productForm.stockLevelsDesc'), columns: 2 },\n { id: 'organization', label: t('inventory.productForm.organization'), description: t('inventory.productForm.organizationDesc'), columns: 2 },\n ],\n facets: [{ field: 'productType', allLabel: t('crud.list.allFacet') }],\n detailTabs: [\n {\n id: 'stock',\n label: t('inventory.productDetail.stockTab'),\n icon: 'Warehouse',\n component: ProductStockTab as never,\n props: { onChanged: onStockChanged },\n },\n ],\n }\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CircleCheck, CircleSlash } from 'lucide-react'\nimport { CrudListView, usePermissionOptional, type CrudBulkAction } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport { useInventoryConfig, useInventoryProvider, useInventoryStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { Product, ProductType } from '../types'\nimport { buildProductEntity } from './productEntity'\n\n// Product list, rendered through the generic CrudListView (header · search ·\n// facet pills · table). One shared EntityDef (buildProductEntity) drives both\n// this list and the create/edit form. Data + routing stay in the inventory\n// store / module nav.\nexport function ProductListView({ onNew, onOpen }: {\n onNew?: () => void\n /** Opens the product's own page. Editing starts there, not from the row. */\n onOpen?: (id: string) => void\n}) {\n const t = useTranslation()\n const can = usePermissionOptional()\n const provider = useInventoryProvider()\n const { currency, productTypes } = useInventoryConfig()\n const products = useInventoryStore((s) => s.products)\n const productsTotal = useInventoryStore((s) => s.productsTotal)\n const productsLoading = useInventoryStore((s) => s.productsLoading)\n const fetchProducts = useInventoryStore((s) => s.fetchProducts)\n\n const [search, setSearch] = useState('')\n const [typeFilter, setTypeFilter] = useState<string | undefined>()\n const [activeFilter, setActiveFilter] = useState<string | undefined>()\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [bulkBusy, setBulkBusy] = useState(false)\n\n // Held in one place: a bulk write has to reload the SAME slice, or the list\n // comes back showing rows the filters exclude.\n const query = useMemo(() => ({\n productType: typeFilter as ProductType | undefined,\n search: search || undefined,\n isActive: activeFilter === undefined ? undefined : activeFilter === 'true',\n }), [typeFilter, search, activeFilter])\n\n useEffect(() => {\n let active = true\n Promise.resolve(fetchProducts(query))\n .finally(() => { if (active) setLoadedOnce(true) })\n return () => { active = false }\n }, [query])\n\n const entity = useMemo(() => buildProductEntity(t, productTypes, currency), [t, productTypes, currency])\n const facets = useMemo(() => [\n {\n field: 'productType',\n allLabel: t('crud.list.allFacet'),\n options: productTypes.map((p) => ({ value: p.value, label: p.label })),\n },\n {\n field: 'isActive',\n label: t('inventory.productList.filterStatus'),\n allLabel: t('inventory.productList.filterAllStatuses'),\n options: [\n { value: 'true', label: t('inventory.productList.filterActive') },\n { value: 'false', label: t('inventory.productList.filterInactive') },\n ],\n },\n ], [productTypes, t])\n\n // --- Bulk: turn products on and off --------------------------------------\n // There is no delete in the provider — a product with stock history cannot\n // just vanish — so \"off the shelf\" is `isActive: false`, which is reversible.\n const runBulk = useCallback(async (rows: Product[], isActive: boolean) => {\n const targets = rows.filter((p) => (p.isActive ?? true) !== isActive)\n if (targets.length === 0) {\n toast.error(t('inventory.productList.bulkNothingToDo'))\n return\n }\n setBulkBusy(true)\n let done = 0\n let failed = 0\n for (const product of targets) {\n try {\n await provider.updateProduct(product.id, { isActive })\n done++\n } catch (err: unknown) {\n failed++\n console.warn('[inventory] updateProduct failed', product.id, err)\n }\n }\n setBulkBusy(false)\n await fetchProducts(query)\n if (done > 0) toast.success(t(isActive ? 'inventory.productList.bulkActivated' : 'inventory.productList.bulkDeactivated', { count: String(done) }))\n if (failed > 0) toast.error(t('inventory.productList.bulkFailed', { count: String(failed) }))\n }, [provider, fetchProducts, query, t])\n\n const bulkActions = useMemo<CrudBulkAction<Product>[] | undefined>(() => {\n if (!can('inventory', 'edit')) return undefined\n return [\n {\n id: 'deactivate',\n label: t('inventory.productList.bulkDeactivate'),\n icon: CircleSlash,\n disabled: bulkBusy,\n onSelect: (rows) => void runBulk(rows, false),\n },\n {\n id: 'activate',\n label: t('inventory.productList.bulkActivate'),\n icon: CircleCheck,\n overflow: true,\n disabled: bulkBusy,\n onSelect: (rows) => void runBulk(rows, true),\n },\n ]\n }, [can, bulkBusy, runBulk, t])\n\n return (\n <CrudListView<Product>\n entityDef={entity}\n items={loadedOnce ? products : null}\n total={productsTotal}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.productList.searchPlaceholder')}\n facets={facets}\n activeFilters={{ productType: typeFilter, isActive: activeFilter }}\n onFacetChange={(field, value) => {\n if (field === 'isActive') setActiveFilter(value)\n else setTypeFilter(value)\n }}\n bulkActions={bulkActions}\n onNew={onNew}\n // O produto É alcançável pelo agente: o plugin o publica em\n // `queryEntities` com `writable: true`, então `createRecord` resolve o\n // alvo e a porta leva a algum lugar. Ver CrudListView.aiCreate.\n aiCreate={{\n hint: t('inventory.productList.askPlaceholder'),\n description: t('inventory.productList.aiHint'),\n intro: {\n role: 'operations',\n persona: t('inventory.productList.askPersona'),\n pitch: t('inventory.productList.askPitch'),\n description: t('inventory.productList.askDescription'),\n suggestions: [0, 1, 2].map((i) => ({ label: t(`inventory.productList.askSuggestion.${i}`) })),\n },\n }}\n addLabel={t('inventory.productList.newProduct')}\n onRowClick={(row) => onOpen?.((row as { id: string }).id)}\n feature=\"inventory\"\n />\n )\n}\n","import React from 'react'\nimport { SubpageHeader, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { CrudFormPage, CrudFormSkeleton, useLimitGuard, invalidateLimit, invalidateRelationOptions } from '@fayz-ai/admin'\nimport { useInventoryConfig, useInventoryStore, useInventoryProvider } from '../context'\nimport type { ProductType } from '../types'\nimport { buildProductEntity } from './productEntity'\n\n// ---------------------------------------------------------------------------\n// Product create/edit, rendered through the generic CRUD form. The sectioned\n// layout (General Information · Classification · Pricing+Margin · Stock Levels)\n// comes from the shared buildProductEntity (segmented/computed/currency field\n// types). Persistence still flows through the inventory provider/store, so the\n// metadata-JSON column mapping is unchanged.\n// ---------------------------------------------------------------------------\n\nexport function ProductCrudForm({ editId, onSaved }: { editId?: string; onSaved?: () => void }) {\n const t = useTranslation()\n const { productTypes, currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n const createProduct = useInventoryStore((s) => s.createProduct)\n const guardProducts = useLimitGuard('products')\n const isEdit = !!editId\n\n const [initialData, setInitialData] = React.useState<Record<string, any> | null>(isEdit ? null : {})\n const [headerName, setHeaderName] = React.useState('')\n const [referenceDataReady, setReferenceDataReady] = React.useState(false)\n\n // Relation selects fetch immediately when the generic form mounts. Prepare\n // the tenant first, then clear any empty result cached by an earlier visit.\n // A provider without this optional capability keeps working unchanged.\n React.useEffect(() => {\n let cancelled = false\n ;(async () => {\n try {\n await provider.ensureReferenceData?.()\n invalidateRelationOptions()\n } catch (error) {\n // Do not turn a reference-data permission problem into a blank form;\n // the select remains usable with whatever rows could be read.\n console.warn('[inventory] Could not prepare reference data', error)\n } finally {\n if (!cancelled) setReferenceDataReady(true)\n }\n })()\n return () => { cancelled = true }\n }, [provider])\n\n // Load the existing product for edit and map it to flat form values.\n React.useEffect(() => {\n if (!editId) return\n let cancelled = false\n ;(async () => {\n const p = await provider.getProductById(editId)\n if (cancelled) return\n setHeaderName(p?.name ?? '')\n setInitialData(\n p\n ? {\n name: p.name,\n id: p.id,\n imageUrl: p.imageUrl,\n brand: p.brand ?? '',\n sku: p.sku ?? '',\n barcode: p.barcode ?? '',\n description: p.description ?? '',\n productType: p.productType,\n costPrice: p.costPrice,\n salePrice: p.salePrice ?? 0,\n minQuantity: p.minQuantity,\n maxQuantity: p.maxQuantity ?? 0,\n categoryId: p.categoryId ?? '',\n measurementUnitId: p.measurementUnitId ?? '',\n supplierId: p.supplierId ?? '',\n defaultLocationId: p.defaultLocationId ?? '',\n }\n : {},\n )\n })()\n return () => { cancelled = true }\n }, [editId])\n\n const entity = React.useMemo(\n () => buildProductEntity(t, productTypes, currency, undefined, provider),\n [t, productTypes, currency, provider],\n )\n\n async function save(values: Record<string, any>) {\n const name = String(values.name ?? '').trim()\n if (!name) { toast.error(t('common.formIncomplete')); throw new Error('name required') }\n const productType = (values.productType ?? productTypes[0]?.value) as ProductType\n const payload = {\n name,\n sku: values.sku || undefined,\n barcode: values.barcode || undefined,\n brand: values.brand || undefined,\n productType,\n costPrice: Number(values.costPrice) || 0,\n // Switching a menu item back to an input must clear the old commercial\n // price as well as hide it; otherwise reports would keep treating the\n // ingredient as sellable even though the form no longer showed why.\n salePrice: productType === 'sale' ? (Number(values.salePrice) || undefined) : 0,\n minQuantity: Number(values.minQuantity) || 0,\n maxQuantity: Number(values.maxQuantity) || undefined,\n description: values.description || undefined,\n // Always sent, even when empty: an empty string clears the link, and\n // `undefined` would leave the previous value in place on edit.\n categoryId: values.categoryId ?? '',\n measurementUnitId: values.measurementUnitId ?? '',\n supplierId: values.supplierId ?? '',\n defaultLocationId: values.defaultLocationId ?? '',\n }\n const imageFile = typeof File !== 'undefined' && values._imageFile instanceof File\n ? values._imageFile\n : undefined\n if (isEdit && editId) {\n await provider.updateProduct(editId, payload)\n if (imageFile && provider.uploadProductImage) await provider.uploadProductImage(editId, imageFile)\n } else {\n // Plan quantity guard (client-side, before the provider call). Opens the\n // global UpgradeModal and aborts when the plan's product cap is reached.\n if ((await guardProducts()) === 'blocked') return\n const created = await createProduct(payload)\n if (imageFile && provider.uploadProductImage) {\n try {\n await provider.uploadProductImage(created.id, imageFile)\n } catch (error) {\n // The product already exists. Do not leave the create form in a state\n // where a retry silently creates a duplicate; report only the media\n // failure and let the user replace the photo from edit mode.\n toast.error('Produto criado, mas a foto não foi enviada.', {\n description: error instanceof Error ? error.message : String(error),\n })\n }\n }\n invalidateLimit('products')\n }\n onSaved?.()\n }\n\n const title = isEdit ? (headerName || t('inventory.productForm.editProduct')) : t('inventory.productForm.newProduct')\n const subtitle = isEdit ? undefined : t('inventory.productForm.addToCatalog')\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader title={title} subtitle={subtitle} onBack={onSaved} parentLabel={t('inventory.nav.products')} />\n {/* Enquanto o produto carrega, a forma do formulário — não o vazio. Sem\n isto a tela ficava só com o cabeçalho e uma área em branco, e o\n conteúdo aparecia de uma vez empurrando tudo. */}\n {(!initialData || !referenceDataReady) && <CrudFormSkeleton hideBreadcrumb />}\n {initialData && referenceDataReady && (\n <CrudFormPage\n entityDef={entity}\n mode={isEdit ? 'edit' : 'create'}\n initialData={initialData}\n onSubmit={save}\n onCancel={() => onSaved?.()}\n namePlural={t('inventory.nav.products')}\n hideBreadcrumb\n />\n )}\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Package } from 'lucide-react'\nimport { CrudDetailPage } from '@fayz-ai/admin'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider } from '../context'\nimport type { Product } from '../types'\nimport { buildProductEntity } from './productEntity'\n\nfunction DetailSkeleton() {\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-20 w-20 rounded-2xl bg-muted/40 animate-pulse\" />\n <div className=\"space-y-2 flex-1\">\n <div className=\"h-6 w-56 rounded bg-muted/40 animate-pulse\" />\n <div className=\"h-3 w-32 rounded bg-muted/30 animate-pulse\" />\n </div>\n </div>\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => <div key={i} className=\"h-3.5 rounded bg-muted/30 animate-pulse\" />)}\n </div>\n </div>\n )\n}\n\n/** The product's own page — overview plus the tabs the entity declares. */\nexport function ProductDetailView({ productId, initialTab, onBack, onEdit }: {\n productId: string\n initialTab?: string\n onBack: () => void\n onEdit?: () => void\n}) {\n const t = useTranslation()\n const { currency, productTypes } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [product, setProduct] = useState<Product | null>(null)\n const [loading, setLoading] = useState(true)\n const [reloadKey, setReloadKey] = useState(0)\n\n // Handed to the Stock tab: undoing a movement changes the on-hand shown here.\n const reload = useCallback(() => setReloadKey((k) => k + 1), [])\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider.getProductById(productId)\n .then((p) => { if (active) setProduct(p) })\n .finally(() => { if (active) setLoading(false) })\n return () => { active = false }\n }, [productId, provider, reloadKey])\n\n const entity = useMemo(\n () => buildProductEntity(t, productTypes, currency, reload),\n [t, productTypes, currency, reload],\n )\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.nav.products')} onBack={onBack} />\n <DetailSkeleton />\n </div>\n )\n }\n\n if (!product) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.nav.products')} onBack={onBack} />\n <div className=\"flex flex-col items-center justify-center py-16 text-center rounded-lg border-2 border-dashed border-muted\">\n <Package className=\"h-8 w-8 text-muted-foreground/30 mb-2\" />\n <p className=\"text-sm text-muted-foreground\">{t('inventory.productDetail.notFound')}</p>\n <button onClick={onBack} className=\"text-xs text-primary hover:underline mt-1\">\n {t('inventory.productDetail.backToList')}\n </button>\n </div>\n </div>\n )\n }\n\n return (\n <CrudDetailPage\n entityDef={entity}\n item={product as unknown as Record<string, any>}\n namePlural={t('inventory.nav.products')}\n basePath=\"/inventory/products\"\n initialTab={initialTab}\n onBack={onBack}\n onEdit={onEdit}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useState, useEffect, useMemo } from 'react'\nimport { Save, Plus, ArrowUpRight, ArrowDownRight, RefreshCw, ArrowRightLeft, Trash2, Package, Check, Eye, Building2 } from 'lucide-react'\nimport { useInventoryConfig, useInventoryStore, useInventoryProvider, formatCurrency } from '../context'\nimport { cn } from '@fayz-ai/ui'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SearchSelect, type SearchSelectOption } from '@fayz-ai/ui'\nimport { DatePicker } from '@fayz-ai/ui'\nimport type { MovementType, StockMovement, StockPosition, Supplier } from '../types'\nimport { MOVEMENT_TYPE_VALUES } from '../lib/movement-vocabulary'\n\n// ---------------------------------------------------------------------------\n// Movement type config\n// ---------------------------------------------------------------------------\n\n// Presentation only. Typed as a Record so TypeScript refuses to compile if a\n// MovementType is ever added to the union and not given a card here — the array\n// this used to be would just have silently omitted it from the picker.\nconst MOVEMENT_TYPE_PRESENTATION: Record<MovementType, { labelKey: string; icon: React.ElementType; color: string; activeColor: string; descKey: string }> = {\n entry: { labelKey: 'inventory.stock.entryLabel', icon: ArrowDownRight, color: 'text-success', activeColor: 'border-success bg-success/10 text-success dark:bg-success/10', descKey: 'inventory.stock.entryDesc' },\n exit: { labelKey: 'inventory.stock.exitLabel', icon: ArrowUpRight, color: 'text-destructive', activeColor: 'border-destructive bg-destructive/10 text-destructive dark:bg-destructive/10', descKey: 'inventory.stock.exitDesc' },\n adjustment: { labelKey: 'inventory.stock.adjustmentLabel', icon: RefreshCw, color: 'text-info', activeColor: 'border-info bg-info/10 text-info dark:bg-info/10', descKey: 'inventory.stock.adjustmentDesc' },\n transfer: { labelKey: 'inventory.stock.transferLabel', icon: ArrowRightLeft, color: 'text-magic', activeColor: 'border-magic bg-magic/10 text-magic dark:bg-magic/10', descKey: 'inventory.stock.transferDesc' },\n loss: { labelKey: 'inventory.stock.lossLabel', icon: Trash2, color: 'text-warning', activeColor: 'border-warning bg-warning/10 text-warning dark:bg-warning/10', descKey: 'inventory.stock.lossDesc' },\n}\n\n// Order comes from the canonical vocabulary, so the picker and any importer\n// agree on both the set and its order.\nconst MOVEMENT_TYPES = MOVEMENT_TYPE_VALUES.map((value) => ({ value, ...MOVEMENT_TYPE_PRESENTATION[value] }))\n\n// ---------------------------------------------------------------------------\n// Movement detail card (for viewing a recorded movement)\n// ---------------------------------------------------------------------------\n\nfunction MovementDetail({ movement, currency, onClose }: {\n movement: StockMovement\n currency: { code: string; locale: string; symbol: string }\n onClose: () => void\n}) {\n const t = useTranslation()\n const typeConfig = MOVEMENT_TYPES.find((mt) => mt.value === movement.movementType)\n const TypeIcon = typeConfig?.icon ?? Package\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title={movement.productName ?? `#${movement.id.slice(0, 8)}`} onBack={onClose} parentLabel={t('inventory.nav.stock')} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n {/* Type + Product hero */}\n <div className=\"flex items-center gap-3\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-xl ${typeConfig?.activeColor ?? 'bg-muted'}`}>\n <TypeIcon className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"text-lg font-bold\">{movement.productName ?? t('inventory.stock.unknownProduct')}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">{movement.movementType} · {movement.movementDate}</p>\n </div>\n </div>\n\n {/* Key details grid */}\n <div className=\"grid gap-3 sm:grid-cols-3 pt-2 border-t\">\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.quantityLabel')}</p>\n <p className=\"text-sm font-semibold\">{movement.movementType === 'entry' ? '+' : '-'}{movement.quantity}</p>\n </div>\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.unitCostLabel')}</p>\n <p className=\"text-sm font-semibold\">{formatCurrency(movement.unitCost, currency)}</p>\n </div>\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.totalCost')}</p>\n <p className=\"text-sm font-semibold\">{formatCurrency(movement.totalCost, currency)}</p>\n </div>\n </div>\n\n {/* Optional details */}\n <div className=\"grid gap-3 sm:grid-cols-2 pt-2 border-t\">\n {movement.stockLocationName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.locationLabel')}</p>\n <p className=\"text-sm\">{movement.stockLocationName}</p>\n </div>\n )}\n {movement.destinationLocationName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.destination')}</p>\n <p className=\"text-sm\">{movement.destinationLocationName}</p>\n </div>\n )}\n {movement.supplierName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.supplier')}</p>\n <p className=\"text-sm\">{movement.supplierName}</p>\n </div>\n )}\n {movement.documentNumber && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.document')}</p>\n <p className=\"text-sm\">{movement.documentNumber}</p>\n </div>\n )}\n {movement.reason && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.reasonLabel')}</p>\n <p className=\"text-sm\">{movement.reason}</p>\n </div>\n )}\n </div>\n\n {movement.notes && (\n <div className=\"pt-2 border-t\">\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.notes')}</p>\n <p className=\"text-sm mt-0.5\">{movement.notes}</p>\n </div>\n )}\n\n <div className=\"pt-2 border-t\">\n <p className=\"text-[10px] text-muted-foreground\">{t('inventory.stock.recorded')} {new Date(movement.createdAt).toLocaleString()}</p>\n </div>\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Stock movement form\n// ---------------------------------------------------------------------------\n\nexport function StockMovementView({ defaultType, onSaved, viewMovement }: {\n defaultType: MovementType\n onSaved?: () => void\n viewMovement?: StockMovement\n}) {\n const t = useTranslation()\n const { currency, modules } = useInventoryConfig()\n const provider = useInventoryProvider()\n const products = useInventoryStore((s) => s.products)\n const locations = useInventoryStore((s) => s.locations)\n const fetchProducts = useInventoryStore((s) => s.fetchProducts)\n const fetchLocations = useInventoryStore((s) => s.fetchLocations)\n const createMovement = useInventoryStore((s) => s.createMovement)\n\n const [step, setStep] = useState(1)\n const [positions, setPositions] = useState<StockPosition[]>([])\n const [movementType, setMovementType] = useState<MovementType>(defaultType)\n const [productId, setProductId] = useState('')\n const [productLabel, setProductLabel] = useState('')\n const [quantity, setQuantity] = useState(1)\n const [unitCost, setUnitCost] = useState(0)\n const [locationId, setLocationId] = useState('')\n const [destLocationId, setDestLocationId] = useState('')\n const [reason, setReason] = useState('')\n const [documentNumber, setDocumentNumber] = useState('')\n const [notes, setNotes] = useState('')\n const [batchNumber, setBatchNumber] = useState('')\n const [expirationDate, setExpirationDate] = useState('')\n const [suppliers, setSuppliers] = useState<Supplier[]>([])\n const [supplierId, setSupplierId] = useState('')\n const [supplierLabel, setSupplierLabel] = useState('')\n const [saving, setSaving] = useState(false)\n const [savedMovement, setSavedMovement] = useState<StockMovement | null>(null)\n\n useEffect(() => { fetchProducts({}); fetchLocations() }, [])\n\n // Only an entry has a supplier — goods leaving never came from one.\n useEffect(() => {\n if (movementType !== 'entry' || suppliers.length > 0) return\n provider.getSuppliers().then(setSuppliers).catch(() => setSuppliers([]))\n }, [movementType])\n\n // Build a map of locationId → total quantity from positions.\n // NOTE: these useMemo hooks must run before the early returns below, otherwise\n // saving (which flips savedMovement) renders fewer hooks → React error.\n const positionByLocation = useMemo(() => {\n const map: Record<string, number> = {}\n for (const pos of positions) {\n if (pos.stockLocationId) {\n map[pos.stockLocationId] = (map[pos.stockLocationId] ?? 0) + pos.quantity\n }\n }\n return map\n }, [positions])\n\n // Sort locations by stock position (highest first)\n const sortedLocations = useMemo(() => {\n return [...locations].sort((a, b) => (positionByLocation[b.id] ?? 0) - (positionByLocation[a.id] ?? 0))\n }, [locations, positionByLocation])\n\n // If viewing a movement detail\n if (viewMovement) {\n return <MovementDetail movement={viewMovement} currency={currency} onClose={() => onSaved?.()} />\n }\n\n // If just saved — show success with details\n if (savedMovement) {\n return <MovementDetail movement={savedMovement} currency={currency} onClose={() => onSaved?.()} />\n }\n\n const selectedProduct = products.find((p) => p.id === productId)\n const totalCost = quantity * unitCost\n const typeConfig = MOVEMENT_TYPES.find((t) => t.value === movementType)!\n const needsReason = movementType === 'adjustment' || movementType === 'loss'\n const needsDest = movementType === 'transfer'\n\n // Product search\n function searchProducts(query: string): SearchSelectOption[] {\n const q = query.toLowerCase()\n return products\n .filter((p) => p.name.toLowerCase().includes(q) || p.sku?.toLowerCase().includes(q) || p.barcode?.includes(q))\n .slice(0, 20)\n .map((p) => ({\n id: p.id,\n label: p.name,\n subtitle: [p.sku, `${t('inventory.stock.currentStock')} ${p.currentQuantity}`].filter(Boolean).join(' · '),\n group: p.productType,\n icon: <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />,\n data: p,\n }))\n }\n\n // Auto-fill cost when product selected + fetch positions\n function handleProductSelect(id: string, option: SearchSelectOption | null) {\n setProductId(id)\n setProductLabel(option?.label ?? '')\n if (option?.data?.costPrice && unitCost === 0) {\n setUnitCost(option.data.costPrice)\n }\n // Fetch stock positions per location for this product\n if (id) {\n provider.getPositions(id).then(setPositions).catch(() => setPositions([]))\n } else {\n setPositions([])\n }\n }\n\n function searchSuppliers(query: string): SearchSelectOption[] {\n const q = query.toLowerCase()\n return suppliers\n .filter((s) => s.name.toLowerCase().includes(q) || s.documentNumber?.toLowerCase().includes(q))\n .slice(0, 20)\n .map((s) => ({\n id: s.id,\n label: s.name,\n subtitle: s.documentNumber ?? s.phone,\n icon: <Building2 className=\"h-4 w-4 text-muted-foreground shrink-0\" />,\n }))\n }\n\n const canProceedStep1 = !!productId\n const canProceedStep2 = quantity > 0 && (!needsReason || reason.trim()) && (!needsDest || destLocationId)\n const title = defaultType === 'entry' ? t('inventory.stock.entry') : defaultType === 'exit' ? t('inventory.stock.exit') : t('inventory.stock.movement')\n\n async function handleSave() {\n if (!productId || quantity <= 0) return\n setSaving(true)\n try {\n const movement = await createMovement({\n productId,\n quantity,\n movementType,\n unitCost: unitCost || undefined,\n stockLocationId: locationId || undefined,\n destinationLocationId: destLocationId || undefined,\n reason: reason || undefined,\n documentNumber: documentNumber || undefined,\n notes: notes || undefined,\n batchNumber: batchNumber || undefined,\n expirationDate: expirationDate || undefined,\n supplierId: movementType === 'entry' ? supplierId || undefined : undefined,\n })\n setSavedMovement(movement)\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={title}\n subtitle={t('inventory.stock.stepOf', { step: String(step) })}\n onBack={step > 1 ? () => setStep(step - 1) : onSaved}\n parentLabel={t('inventory.nav.stock')}\n />\n\n {/* Progress bar */}\n <div className=\"flex gap-1\">\n {[1, 2, 3].map((s) => (\n <div key={s} className={`h-1 flex-1 rounded-full transition-colors ${s <= step ? 'bg-primary' : 'bg-muted'}`} />\n ))}\n </div>\n\n {/* Step 1: What — Type + Product */}\n {step === 1 && (\n <div className=\"space-y-5\">\n {/* Movement type selector */}\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">{t('inventory.stock.movementType')}</p>\n <div className=\"grid gap-2 sm:grid-cols-5\">\n {MOVEMENT_TYPES.map((mt) => {\n const Icon = mt.icon\n const active = movementType === mt.value\n return (\n <button\n key={mt.value}\n onClick={() => setMovementType(mt.value)}\n className={`rounded-lg border-2 p-3 text-left transition-all ${active ? mt.activeColor : 'border-transparent bg-card hover:bg-muted/30'}`}\n >\n <Icon className=\"h-4 w-4 mb-1\" />\n <p className=\"text-xs font-medium\">{t(mt.labelKey)}</p>\n <p className=\"text-[9px] text-muted-foreground mt-0.5 hidden sm:block\">{t(mt.descKey)}</p>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Product search */}\n <SearchSelect\n value={productId}\n displayValue={productLabel}\n onChange={handleProductSelect}\n onSearch={searchProducts}\n label={t('inventory.stock.product')}\n required\n placeholder={t('inventory.stock.searchProduct')}\n minChars={1}\n debounce={150}\n renderOption={(opt) => (\n <>\n {opt.icon}\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm truncate\">{opt.label}</p>\n {opt.subtitle && <p className=\"text-[10px] text-muted-foreground\">{opt.subtitle}</p>}\n </div>\n </>\n )}\n />\n\n {selectedProduct && (\n <div className=\"rounded-lg bg-muted/30 px-4 py-3 flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-medium\">{selectedProduct.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.stock.currentStock')} <span className=\"font-medium\">{selectedProduct.currentQuantity}</span>\n {selectedProduct.minQuantity > 0 && <> · Min: {selectedProduct.minQuantity}</>}\n {selectedProduct.costPrice > 0 && <> · Cost: {formatCurrency(selectedProduct.costPrice, currency)}</>}\n </p>\n </div>\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[9px] font-medium bg-muted text-muted-foreground capitalize\">{selectedProduct.productType}</span>\n </div>\n )}\n\n <div className=\"flex justify-end\">\n <button\n onClick={() => setStep(2)}\n disabled={!canProceedStep1}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\"\n >\n {t('inventory.stock.next')}\n </button>\n </div>\n </div>\n )}\n\n {/* Step 2: How much — Quantity + Cost + Location */}\n {step === 2 && (\n <div className=\"space-y-5\">\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.quantity')}</label>\n <input\n type=\"number\"\n min={0.01}\n step={0.01}\n value={quantity}\n onChange={(e) => setQuantity(Number(e.target.value) || 0)}\n autoFocus\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.unitCost')}</label>\n <div className=\"flex items-center mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus-within:ring-2 focus-within:ring-primary/20\">\n <span className=\"pl-2.5 text-xs text-muted-foreground\">{currency.symbol}</span>\n <input type=\"number\" min={0} step={0.01} value={unitCost} onChange={(e) => setUnitCost(Number(e.target.value) || 0)} className=\"flex-1 bg-transparent px-2 py-2 text-sm outline-none\" />\n </div>\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.total')}</label>\n <p className=\"mt-1 px-3 py-2 text-lg font-bold\">{formatCurrency(totalCost, currency)}</p>\n </div>\n </div>\n\n {/* Location — radio-style selector with stock positions */}\n {modules.stockLocations && locations.length > 0 && (\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{needsDest ? t('inventory.stock.fromLocation') : t('inventory.stock.locationLabel')}</label>\n <div className=\"flex flex-wrap gap-2 mt-1.5\">\n {sortedLocations.map((l) => {\n const qty = positionByLocation[l.id] ?? 0\n return (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => setLocationId(l.id)}\n className={cn(\n 'rounded-button border-2 px-3 py-2 text-sm font-medium transition-all flex items-center gap-2',\n locationId === l.id\n ? 'border-primary bg-primary/5 text-primary'\n : 'border-transparent bg-muted/30 text-muted-foreground hover:bg-muted/50',\n )}\n >\n <span>{l.name}</span>\n {productId && (\n <span className={cn(\n 'inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold tabular-nums',\n qty > 0\n ? 'bg-success/10 text-success'\n : 'bg-muted text-muted-foreground',\n )}>\n {qty}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n {needsDest && (\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.toLocation')}</label>\n <div className=\"flex flex-wrap gap-2 mt-1.5\">\n {sortedLocations.filter((l) => l.id !== locationId).map((l) => {\n const qty = positionByLocation[l.id] ?? 0\n return (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => setDestLocationId(l.id)}\n className={cn(\n 'rounded-button border-2 px-3 py-2 text-sm font-medium transition-all flex items-center gap-2',\n destLocationId === l.id\n ? 'border-primary bg-primary/5 text-primary'\n : 'border-transparent bg-muted/30 text-muted-foreground hover:bg-muted/50',\n )}\n >\n <span>{l.name}</span>\n {productId && (\n <span className={cn(\n 'inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold tabular-nums',\n qty > 0\n ? 'bg-success/10 text-success'\n : 'bg-muted text-muted-foreground',\n )}>\n {qty}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Reason (required for adjustment/loss) */}\n {needsReason && (\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.reason')}</label>\n <input type=\"text\" value={reason} onChange={(e) => setReason(e.target.value)} placeholder={movementType === 'loss' ? t('inventory.stock.reasonLossPlaceholder') : t('inventory.stock.reasonAdjustPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n </div>\n\n <div className=\"flex justify-between\">\n <button onClick={() => setStep(1)} className=\"rounded-lg border px-4 py-2 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">{t('inventory.stock.back')}</button>\n <button onClick={() => setStep(3)} disabled={!canProceedStep2} className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\">{t('inventory.stock.next')}</button>\n </div>\n </div>\n )}\n\n {/* Step 3: Review + Optional details + Save */}\n {step === 3 && (\n <div className=\"space-y-5\">\n {/* Summary card */}\n <div className=\"rounded-card border bg-card shadow-sm p-5\">\n <div className=\"flex items-center gap-3 mb-4\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-xl ${typeConfig.activeColor}`}>\n <typeConfig.icon className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{productLabel}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">{movementType} · {quantity} units · {formatCurrency(totalCost, currency)}</p>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3 text-xs border-t pt-3\">\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.quantityLabel')}:</span> <span className=\"font-medium\">{quantity}</span></div>\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.unitCostLabel')}:</span> <span className=\"font-medium\">{formatCurrency(unitCost, currency)}</span></div>\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.total')}:</span> <span className=\"font-bold\">{formatCurrency(totalCost, currency)}</span></div>\n </div>\n </div>\n\n {/* Optional details */}\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <p className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.additionalDetails')}</p>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {movementType === 'entry' && (\n <SearchSelect\n value={supplierId}\n displayValue={supplierLabel}\n onChange={(id, option) => { setSupplierId(id); setSupplierLabel(option?.label ?? '') }}\n onSearch={searchSuppliers}\n label={t('inventory.stock.supplier')}\n placeholder={t('inventory.stock.searchSupplier')}\n noResultsLabel={t('inventory.stock.noSuppliers')}\n minChars={1}\n debounce={150}\n />\n )}\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.documentNumber')}</label>\n <input type=\"text\" value={documentNumber} onChange={(e) => setDocumentNumber(e.target.value)} placeholder={t('inventory.stock.documentPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n {modules.batchTracking && (\n <>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.batchNumber')}</label>\n <input type=\"text\" value={batchNumber} onChange={(e) => setBatchNumber(e.target.value)} placeholder={t('inventory.stock.batchPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.expirationDate')}</label>\n <DatePicker value={expirationDate} onChange={setExpirationDate} className=\"mt-1\" />\n </div>\n </>\n )}\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.notes')}</label>\n <textarea value={notes} onChange={(e) => setNotes(e.target.value)} rows={2} placeholder={t('inventory.stock.notesPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n </div>\n\n <div className=\"flex justify-between\">\n <button onClick={() => setStep(2)} className=\"rounded-lg border px-4 py-2 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">{t('inventory.stock.back')}</button>\n <button\n onClick={handleSave}\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-5 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\"\n >\n <Check className=\"h-3.5 w-3.5\" /> {saving ? t('inventory.stock.recording') : t('inventory.stock.recordMovement')}\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import React, { useEffect, useState, useMemo } from 'react'\nimport { ArrowUpRight, ArrowDownRight, RefreshCw, ArrowRightLeft, Trash2 } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ListView, Button } from '@fayz-ai/ui'\nimport { useInventoryStore, formatCurrency, useInventoryConfig } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport type { MovementType, StockMovement } from '../types'\nimport { movementTypeSpec } from '../lib/movement-vocabulary'\n\nconst TYPE_ICONS: Record<MovementType, React.ElementType> = {\n entry: ArrowDownRight,\n exit: ArrowUpRight,\n adjustment: RefreshCw,\n transfer: ArrowRightLeft,\n loss: Trash2,\n}\n\n/** Translated label for a movement type; falls back to the raw value. */\nfunction movementTypeLabel(type: MovementType, t: (k: string) => string): string {\n const spec = movementTypeSpec(type)\n return spec ? t(spec.labelKey) : type\n}\n\nconst TYPE_COLORS: Record<MovementType, string> = {\n entry: 'text-success',\n exit: 'text-destructive',\n adjustment: 'text-info',\n transfer: 'text-magic',\n loss: 'text-warning',\n}\n\nexport function MovementHistoryView({ onViewDetail, onNew, onNewExit }: {\n onViewDetail?: (id: string) => void\n /** Record an entry. This screen is where you already are when the goods arrive. */\n onNew?: () => void\n onNewExit?: () => void\n} = {}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const movements = useInventoryStore((s) => s.movements)\n const movementsLoading = useInventoryStore((s) => s.movementsLoading)\n const fetchMovements = useInventoryStore((s) => s.fetchMovements)\n\n const [search, setSearch] = useState('')\n\n useEffect(() => { fetchMovements({ search: search || undefined }) }, [search])\n\n const columns: ColumnDef<StockMovement, any>[] = useMemo(() => [\n {\n accessorKey: 'movementDate', header: t('inventory.history.columnDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{getValue() as string}</span>,\n },\n {\n accessorKey: 'productName', header: t('inventory.history.columnProduct'),\n cell: ({ getValue }: any) => <span className=\"font-medium\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'movementType', header: t('inventory.history.columnType'),\n cell: ({ getValue }: any) => {\n const type = getValue() as MovementType\n const Icon = TYPE_ICONS[type] ?? RefreshCw\n const color = TYPE_COLORS[type] ?? 'text-muted-foreground'\n return (\n <span className={`inline-flex items-center gap-1 ${color}`}>\n <Icon className=\"h-3 w-3\" />\n <span className=\"text-xs\">{movementTypeLabel(type, t)}</span>\n </span>\n )\n },\n },\n {\n id: 'location', header: t('inventory.history.columnLocation'),\n cell: ({ row }: any) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.stockLocationName ?? '—'}\n {row.original.movementType === 'transfer' && row.original.destinationLocationName && (\n <span> → {row.original.destinationLocationName}</span>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'quantity', header: t('inventory.history.columnQty'),\n cell: ({ row }: any) => (\n <span className=\"text-right block\">\n {row.original.movementType === 'entry' ? '+' : '-'}{row.original.quantity}\n </span>\n ),\n },\n {\n accessorKey: 'totalCost', header: t('inventory.history.columnTotal'),\n cell: ({ getValue }: any) => (\n <span className=\"text-right block text-muted-foreground\">{formatCurrency(getValue() as number, currency)}</span>\n ),\n },\n ], [currency, t])\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title={t('inventory.history.title')} subtitle={t('inventory.history.subtitle')} />\n\n <ListView<StockMovement>\n columns={columns}\n data={movements}\n loading={movementsLoading}\n searchPlaceholder={t('inventory.history.searchPlaceholder')}\n search={search}\n onSearchChange={setSearch}\n searchDebounce={0}\n onRowClick={onViewDetail ? (row) => onViewDetail(row.id) : undefined}\n newLabel={onNew ? t('inventory.history.newEntry') : undefined}\n onNew={onNew}\n headerActions={onNewExit ? (\n <Button variant=\"outline\" size=\"sm\" onClick={onNewExit}>\n <ArrowUpRight className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('inventory.history.newExit')}\n </Button>\n ) : undefined}\n emptyMessage={t('inventory.history.noMovements')}\n emptyActionLabel={onNew ? t('inventory.history.newEntry') : undefined}\n onEmptyAction={onNew}\n />\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CrudListView } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { CountSessionStatus, StockCountSession } from '../types'\n\nconst STATUS_TONE: Record<CountSessionStatus, string> = {\n open: 'bg-muted text-muted-foreground',\n counting: 'bg-info-soft text-info-soft-foreground',\n closed: 'bg-success-soft text-success-soft-foreground',\n cancelled: 'bg-muted text-muted-foreground line-through',\n}\n\nfunction buildCountEntity(t: (key: string, params?: Record<string, string>) => string): EntityDef {\n return {\n name: t('inventory.counts.entity'),\n namePlural: t('inventory.counts.title'),\n icon: 'ClipboardList',\n displayField: 'label',\n fields: [\n {\n key: 'label', label: t('inventory.counts.colReference'), type: 'text', searchable: true,\n renderCell: (_v, row: any) => (\n <div>\n <p className=\"font-medium\">{row.label}</p>\n <p className=\"text-xs text-muted-foreground\">{row.stockLocationName ?? '—'}</p>\n </div>\n ),\n },\n {\n key: 'openedAt', label: t('inventory.counts.colOpened'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className=\"text-xs text-muted-foreground\">{row.openedAt?.slice(0, 10) ?? '—'}</span>\n ),\n },\n {\n key: 'status', label: t('inventory.counts.colStatus'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${STATUS_TONE[row.status as CountSessionStatus]}`}>\n {t(`inventory.counts.status.${row.status}`)}\n </span>\n ),\n },\n {\n key: 'progress', label: t('inventory.counts.colProgress'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums text-muted-foreground\">\n {t('inventory.counts.progress', { counted: String(row.countedCount ?? 0), total: String(row.itemCount ?? 0) })}\n </span>\n ),\n },\n {\n key: 'divergentCount', label: t('inventory.counts.colDivergent'), type: 'number',\n renderCell: (_v, row: any) => (\n <span className={`block text-right tabular-nums ${row.divergentCount ? 'font-medium text-warning-soft-foreground' : 'text-muted-foreground'}`}>\n {row.divergentCount ?? 0}\n </span>\n ),\n },\n ],\n }\n}\n\n/** The counts a tenant has run — and the way into a new one. */\nexport function StockCountsView({ onNew, onOpen }: {\n onNew?: () => void\n onOpen?: (id: string) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n const [sessions, setSessions] = useState<StockCountSession[]>([])\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [search, setSearch] = useState('')\n\n const load = useCallback(async () => {\n setSessions(await provider.getCountSessions())\n setLoadedOnce(true)\n }, [provider])\n\n useEffect(() => { void load() }, [load])\n\n const rows = useMemo(() => {\n const term = search.trim().toLowerCase()\n return sessions\n .map((session) => ({\n ...session,\n label: session.reference || `${session.stockLocationName ?? ''} · ${session.openedAt.slice(0, 10)}`.trim(),\n }))\n .filter((row) => !term || row.label.toLowerCase().includes(term))\n }, [sessions, search])\n\n const entity = useMemo(() => buildCountEntity(t), [t])\n\n return (\n <CrudListView\n entityDef={entity}\n items={loadedOnce ? (rows as unknown as Array<{ id: string }>) : null}\n total={rows.length}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.counts.searchPlaceholder')}\n onNew={onNew}\n addLabel={t('inventory.counts.newCount')}\n onRowClick={(row) => onOpen?.((row as { id: string }).id)}\n emptyMessage={t('inventory.counts.empty')}\n onRefresh={() => load()}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Button, SubpageHeader, Switch, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { ProductCategory, StockLocation } from '../types'\n\nconst FIELD =\n 'w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring'\n\n/** Opening a count is four decisions: where, what, blind, and what to call it. */\nexport function StockCountFormView({ onOpened, onCancel }: {\n onOpened: (sessionId: string) => void\n onCancel: () => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n const [locations, setLocations] = useState<StockLocation[]>([])\n const [categories, setCategories] = useState<ProductCategory[]>([])\n const [locationId, setLocationId] = useState('')\n const [categoryId, setCategoryId] = useState('')\n const [reference, setReference] = useState('')\n const [blind, setBlind] = useState(true)\n const [notes, setNotes] = useState('')\n const [saving, setSaving] = useState(false)\n\n useEffect(() => {\n let active = true\n void Promise.all([provider.getLocations(), provider.getCategories()]).then(([locs, cats]) => {\n if (!active) return\n setLocations(locs)\n setCategories(cats)\n if (locs.length === 1) setLocationId(locs[0].id)\n })\n return () => { active = false }\n }, [provider])\n\n async function handleOpen() {\n if (!locationId) return\n setSaving(true)\n try {\n const session = await provider.openCountSession({\n stockLocationId: locationId,\n categoryId: categoryId || undefined,\n reference: reference.trim() || undefined,\n blind,\n notes: notes.trim() || undefined,\n })\n onOpened(session.id)\n } catch (err: any) {\n toast.error(t('inventory.counts.openFailed'), { description: err?.message })\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onCancel} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4 max-w-2xl\">\n <div>\n <h2 className=\"text-sm font-semibold\">{t('inventory.counts.formTitle')}</h2>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.counts.formSubtitle')}</p>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.location')}</label>\n <select className={FIELD} value={locationId} onChange={(e) => setLocationId(e.target.value)}>\n <option value=\"\">{t('inventory.counts.pickLocation')}</option>\n {locations.map((l) => <option key={l.id} value={l.id}>{l.name}</option>)}\n </select>\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.category')}</label>\n <select className={FIELD} value={categoryId} onChange={(e) => setCategoryId(e.target.value)}>\n <option value=\"\">{t('inventory.counts.allCategories')}</option>\n {categories.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}\n </select>\n </div>\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.reference')}</label>\n <input\n type=\"text\" className={FIELD} value={reference}\n onChange={(e) => setReference(e.target.value)}\n placeholder={t('inventory.counts.referencePlaceholder')}\n />\n </div>\n\n <div className=\"rounded-lg bg-muted/30 px-4 py-3 flex items-start justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium\">{t('inventory.counts.blind')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.counts.blindHint')}</p>\n </div>\n <Switch checked={blind} onCheckedChange={setBlind} size=\"md\" />\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.notes')}</label>\n <textarea\n className={FIELD} rows={2} value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder={t('inventory.counts.notesPlaceholder')}\n />\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={onCancel}>{t('inventory.counts.cancel')}</Button>\n <Button onClick={() => void handleOpen()} disabled={!locationId || saving}>\n {saving ? t('inventory.counts.opening') : t('inventory.counts.open')}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n","import type { StockCountItem } from '../types'\n\n// ---------------------------------------------------------------------------\n// Count variance — pure arithmetic, no data access.\n//\n// The one rule everything here enforces: an UNCOUNTED line is not a line that\n// counted zero. `countedQuantity` undefined means nobody looked at the shelf,\n// so it has no variance, it is never divergent, and the close must never emit\n// an adjustment for it. Counting zero is a real answer and is stored as 0.\n// ---------------------------------------------------------------------------\n\nexport function isCounted(item: Pick<StockCountItem, 'countedQuantity'>): boolean {\n return item.countedQuantity !== undefined && item.countedQuantity !== null\n}\n\n/** counted − system, or null when the line was never counted. */\nexport function lineVariance(\n item: Pick<StockCountItem, 'systemQuantity' | 'countedQuantity'>,\n): number | null {\n if (!isCounted(item)) return null\n return (Number(item.countedQuantity) || 0) - (Number(item.systemQuantity) || 0)\n}\n\nexport function isDivergent(\n item: Pick<StockCountItem, 'systemQuantity' | 'countedQuantity'>,\n): boolean {\n const variance = lineVariance(item)\n return variance !== null && variance !== 0\n}\n\nexport interface CountSummary {\n total: number\n counted: number\n uncounted: number\n divergent: number\n /** Net units gained or lost across the divergent lines. */\n variance: number\n /** The same, valued at each line's unit cost — what the close costs. */\n varianceValue: number\n}\n\nexport function summarizeCount(items: StockCountItem[]): CountSummary {\n let counted = 0\n let divergent = 0\n let variance = 0\n let varianceValue = 0\n for (const item of items) {\n const delta = lineVariance(item)\n if (delta === null) continue\n counted += 1\n if (delta === 0) continue\n divergent += 1\n variance += delta\n varianceValue += delta * (Number(item.unitCost) || 0)\n }\n return {\n total: items.length,\n counted,\n uncounted: items.length - counted,\n divergent,\n variance,\n varianceValue,\n }\n}\n\n/** The lines the close will act on, in the order it will act on them. */\nexport function divergentLines(items: StockCountItem[]): StockCountItem[] {\n return items.filter(isDivergent)\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Button, ConfirmDialog, SubpageHeader, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { StockCountItem, StockCountSession } from '../types'\nimport { lineVariance, summarizeCount } from '../lib/stock-count'\n\n/**\n * The counting screen — used standing up, on a phone, in a cold room. One row\n * per product, one big number field, Enter moves to the next line.\n *\n * A blind session hides the system quantity AND the per-line variance until the\n * count is closed. Showing the variance the instant a number is typed would let\n * the counter retype until it reads zero, which is the same rubber stamp blind\n * mode exists to prevent.\n */\nexport function StockCountSessionView({ sessionId, onBack }: {\n sessionId: string\n onBack: () => void\n}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [session, setSession] = useState<StockCountSession | null>(null)\n const [items, setItems] = useState<StockCountItem[]>([])\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [loading, setLoading] = useState(true)\n const [closing, setClosing] = useState(false)\n const [confirmingClose, setConfirmingClose] = useState(false)\n const [confirmingCancel, setConfirmingCancel] = useState(false)\n const inputs = useRef<Array<HTMLInputElement | null>>([])\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n const [head, lines] = await Promise.all([\n provider.getCountSession(sessionId),\n provider.getCountItems(sessionId),\n ])\n setSession(head)\n setItems(lines)\n setDrafts(Object.fromEntries(\n lines.map((l) => [l.id, l.countedQuantity === undefined ? '' : String(l.countedQuantity)]),\n ))\n } finally {\n setLoading(false)\n }\n }, [provider, sessionId])\n\n useEffect(() => { void load() }, [load])\n\n const summary = useMemo(() => summarizeCount(items), [items])\n const closed = session?.status === 'closed' || session?.status === 'cancelled'\n const hideVariance = (session?.blind ?? false) && !closed\n\n async function commit(item: StockCountItem, raw: string) {\n const trimmed = raw.trim()\n const next = trimmed === '' ? null : Number(trimmed)\n if (next !== null && !Number.isFinite(next)) return\n const current = item.countedQuantity ?? null\n if (next === current) return\n try {\n const saved = await provider.saveCountEntry(item.id, next)\n setItems((prev) => prev.map((i) => (i.id === item.id ? { ...i, ...saved } : i)))\n if (session?.status === 'open') setSession({ ...session, status: 'counting' })\n } catch (err: any) {\n toast.error(t('inventory.counts.saveFailed'), { description: err?.message })\n }\n }\n\n async function handleClose() {\n setClosing(true)\n try {\n const result = await provider.closeCountSession(\n sessionId,\n t('inventory.counts.adjustmentReason', { reference: session?.reference ?? '' }),\n )\n toast.success(\n result.alreadyClosed\n ? t('inventory.counts.alreadyClosed')\n : t('inventory.counts.closed', { count: String(result.adjustmentsCreated) }),\n )\n await load()\n } catch (err: any) {\n toast.error(t('inventory.counts.closeFailed'), { description: err?.message })\n } finally {\n setClosing(false)\n setConfirmingClose(false)\n }\n }\n\n async function handleCancel() {\n try {\n await provider.cancelCountSession(sessionId)\n toast.success(t('inventory.counts.cancelled'))\n await load()\n } catch (err: any) {\n toast.error(t('inventory.counts.cancelFailed'), { description: err?.message })\n } finally {\n setConfirmingCancel(false)\n }\n }\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => <div key={i} className=\"h-8 rounded bg-muted/30 animate-pulse\" />)}\n </div>\n </div>\n )\n }\n\n if (!session) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n <div className=\"rounded-card border p-8 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('inventory.counts.notFound')}</p>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-4 flex flex-wrap items-center justify-between gap-4\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold truncate\">\n {session.reference || session.stockLocationName || t('inventory.counts.entity')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {session.stockLocationName ?? '—'}\n {session.categoryName && <> · {session.categoryName}</>}\n {' '}· {t(`inventory.counts.status.${session.status}`)}\n {session.blind && <> · {t('inventory.counts.blind')}</>}\n </p>\n </div>\n <div className=\"flex items-center gap-5 text-xs\">\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.counted')}</p>\n <p className=\"font-semibold tabular-nums\">{summary.counted}/{summary.total}</p>\n </div>\n {!hideVariance && (\n <>\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.divergent')}</p>\n <p className=\"font-semibold tabular-nums\">{summary.divergent}</p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.varianceValue')}</p>\n <p className={`font-semibold tabular-nums ${summary.varianceValue < 0 ? 'text-destructive' : ''}`}>\n {formatCurrency(summary.varianceValue, currency)}\n </p>\n </div>\n </>\n )}\n </div>\n {!closed && (\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setConfirmingCancel(true)}>\n {t('inventory.counts.cancelCount')}\n </Button>\n <Button size=\"sm\" onClick={() => setConfirmingClose(true)}>\n {t('inventory.counts.close')}\n </Button>\n </div>\n )}\n </div>\n\n <div className=\"rounded-card border bg-card shadow-sm divide-y\">\n {items.map((item, index) => {\n const variance = lineVariance(item)\n return (\n <div key={item.id} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{item.productName ?? item.productId}</p>\n <p className=\"text-xs text-muted-foreground\">\n {item.productSku ? `${item.productSku} · ` : ''}\n {hideVariance\n ? t('inventory.counts.blindLine')\n : `${t('inventory.counts.systemQty')} ${item.systemQuantity}`}\n </p>\n </div>\n\n {!hideVariance && (\n <span className={`w-16 shrink-0 text-right text-sm tabular-nums ${\n variance === null ? 'text-muted-foreground'\n : variance === 0 ? 'text-muted-foreground'\n : variance > 0 ? 'text-success' : 'text-destructive'\n }`}>\n {variance === null ? '—' : variance > 0 ? `+${variance}` : variance}\n </span>\n )}\n\n <input\n ref={(el) => { inputs.current[index] = el }}\n type=\"number\"\n inputMode=\"decimal\"\n step=\"0.01\"\n disabled={closed}\n value={drafts[item.id] ?? ''}\n placeholder={t('inventory.counts.notCounted')}\n onChange={(e) => setDrafts((d) => ({ ...d, [item.id]: e.target.value }))}\n onBlur={() => void commit(item, drafts[item.id] ?? '')}\n onKeyDown={(e) => {\n if (e.key !== 'Enter') return\n e.preventDefault()\n inputs.current[index + 1]?.focus()\n }}\n className=\"w-28 shrink-0 rounded-input border border-input bg-card px-3 py-2.5 text-right text-base font-medium tabular-nums shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n )\n })}\n {items.length === 0 && (\n <p className=\"px-4 py-8 text-center text-xs text-muted-foreground\">{t('inventory.counts.noItems')}</p>\n )}\n </div>\n\n <ConfirmDialog\n open={confirmingClose}\n title={t('inventory.counts.closeTitle')}\n description={t('inventory.counts.closeDescription', {\n divergent: String(summary.divergent),\n uncounted: String(summary.uncounted),\n })}\n confirmLabel={t('inventory.counts.closeConfirm')}\n cancelLabel={t('inventory.counts.cancel')}\n loading={closing}\n onConfirm={() => void handleClose()}\n onCancel={() => setConfirmingClose(false)}\n />\n\n <ConfirmDialog\n open={confirmingCancel}\n variant=\"destructive\"\n title={t('inventory.counts.cancelTitle')}\n description={t('inventory.counts.cancelDescription')}\n confirmLabel={t('inventory.counts.cancelConfirm')}\n cancelLabel={t('inventory.counts.cancel')}\n onConfirm={() => void handleCancel()}\n onCancel={() => setConfirmingCancel(false)}\n />\n </div>\n )\n}\n","import type { IngredientCostBasis } from '../types'\n\n// ---------------------------------------------------------------------------\n// Recipe cost and CMV — pure arithmetic, no data access.\n//\n// THE UNIT ASSUMPTION, STATED OUT LOUD.\n//\n// The legacy implementation (beautyplace src/hooks/useRecipeCost.ts) multiplied\n// quantity × price with no conversion at all: it assumes the quantity written\n// on a recipe line is already expressed in the ingredient product's own unit.\n// We keep that assumption, because nothing in the data can contradict it — a\n// recipe line has no unit of its own that we could convert FROM.\n//\n// The one case we do better on is the one a kitchen actually hits: a product\n// bought in boxes and consumed in grams. When a product declares a purchase\n// unit distinct from the unit it is counted in, `products.cost` is the cost of\n// that purchase unit, and `conversionFactor` says how many counted units fit in\n// it — so the per-unit cost is cost ÷ factor. Without a declared purchase unit\n// the factor means nothing and we do exactly what the legacy app did.\n//\n// Artorius has purchase_unit_id NULL and conversion_factor 1 on all 43 rows, so\n// today both branches agree; the branch is the hedge, not a behaviour change.\n// ---------------------------------------------------------------------------\n\n/** Above this the dish eats the margin — the line the legacy app drew. */\nexport const CMV_ALERT_THRESHOLD = 35\n\nexport interface CostableLine {\n quantity: number\n costBasis?: IngredientCostBasis | null\n}\n\nexport interface CostedLine<T> {\n line: T\n /** Cost of one unit as the recipe counts it. */\n unitCost: number\n /** unitCost × quantity. */\n cost: number\n}\n\nexport function ingredientUnitCost(basis?: IngredientCostBasis | null): number {\n if (!basis) return 0\n const cost = Number(basis.cost) || 0\n if (!basis.purchaseUnitId) return cost\n const factor = Number(basis.conversionFactor) || 0\n return factor > 0 ? cost / factor : cost\n}\n\nexport function lineCost(line: CostableLine): number {\n return ingredientUnitCost(line.costBasis) * (Number(line.quantity) || 0)\n}\n\nexport function costLines<T extends CostableLine>(lines: T[]): CostedLine<T>[] {\n return lines.map((line) => {\n const unitCost = ingredientUnitCost(line.costBasis)\n return { line, unitCost, cost: unitCost * (Number(line.quantity) || 0) }\n })\n}\n\nexport function recipeCost(lines: CostableLine[]): number {\n return lines.reduce((sum, line) => sum + lineCost(line), 0)\n}\n\n/** Cost as a percentage of the sale price. Null when there is no price to divide by. */\nexport function cmvPercent(cost: number, salePrice?: number | null): number | null {\n const price = Number(salePrice) || 0\n if (price <= 0) return null\n return ((Number(cost) || 0) / price) * 100\n}\n\nexport function isCmvHigh(cmv: number | null | undefined): boolean {\n return typeof cmv === 'number' && cmv > CMV_ALERT_THRESHOLD\n}\n","import type { PluginAITool } from '@fayz-ai/core'\n\n/**\n * The assistant's ficha-técnica tool. A SERVER-PLANE write (a pool RPC), so it\n * works from any page and any channel and persists straight to the tenant's\n * recipes — the same pattern agenda/financial/forms use.\n *\n * `role: 'finance'` is explicit and load-bearing: the plugin's\n * `defaultAgentRole` is 'operations', and cost per dish is the finance\n * colleague's job (Selma, \"Gerente Administrativa\" in resto-saas). Without it\n * the tool would land on the operations colleague instead.\n *\n * The recipes screen publishes the ingredient CATALOGUE through\n * `useAgentSurface`, so the model sends real product ids; the RPC still\n * resolves names for whatever it names without one.\n */\n\nconst INGREDIENT_SHAPE =\n 'An ingredient line: { product_id?, name, quantity, notes? }. ' +\n 'Prefer product_id from the catalogue in the screen context; send `name` too so an ' +\n 'unmatched line can still be shown to the user. quantity is a number in the ' +\n \"ingredient's own unit — the catalogue lists that unit.\"\n\nexport const upsertRecipeTool: PluginAITool = {\n id: 'inventory.upsertRecipe',\n name: 'upsertRecipe',\n description:\n 'Creates or edits a ficha técnica (recipe) for a menu item: what it is made of, how much it yields and how it is prepared. ' +\n 'Persisted server-side, so it works from ANY page. ' +\n 'Omit recipeId to CREATE (name required); pass recipeId to EDIT. ' +\n 'Propose the WHOLE recipe in a single call — ingredients, quantities, yield and preparation together. Do NOT interview the user ingredient by ingredient. ' +\n 'Use the ingredient catalogue in the screen context to pick real product ids; name anything else in `name` and it will come back flagged for the user to pick or create. ' +\n 'The user confirms before it is saved.',\n icon: 'BookOpen',\n mode: 'persist',\n role: 'finance',\n limitKey: 'recipes',\n permission: { feature: 'inventory.recipes', action: 'create' },\n execution: { plane: 'server', kind: 'rpc', rpc: 'agent_inventory_upsert_recipe' },\n category: 'Inventory',\n suggestions: [\n { label: 'Monte a ficha técnica do cupim defumado com queijo, 400g' },\n { label: 'Quais itens do cardápio ainda não têm ficha técnica?' },\n ],\n parameters: {\n type: 'object',\n properties: {\n recipeId: { type: 'string', description: 'Existing recipe id to EDIT. Omit to create a new one.' },\n name: { type: 'string', description: 'Recipe name — required when creating.' },\n product_id: { type: 'string', description: 'Id of the product this recipe produces, from the screen context.' },\n product_name: { type: 'string', description: 'Name of the produced product, when its id is unknown. Resolved against the catalogue.' },\n description: { type: 'string', description: 'Optional short description.' },\n yield_quantity: { type: 'number', description: 'How many units one batch yields. Defaults to 1.' },\n preparation_time_minutes: { type: 'number', description: 'Preparation time in minutes.' },\n instructions: { type: 'string', description: 'Step-by-step preparation.' },\n ingredients: {\n type: 'array',\n description: `The FULL ingredient list — REPLACES every existing line. Each item: ${INGREDIENT_SHAPE}`,\n items: { type: 'object', description: INGREDIENT_SHAPE },\n },\n },\n },\n}\n\nexport const RECIPE_SURFACE_INSTRUCTIONS = [\n 'Você está na tela de FICHAS TÉCNICAS. Para montar ou editar uma ficha use a tool upsertRecipe (ela persiste no backend).',\n 'O catálogo de insumos (id, nome, unidade, custo) e os itens do cardápio sem ficha estão no JSON da tela em contexto — use os ids de lá em vez de inventar.',\n 'Proponha a ficha inteira numa única chamada: ingredientes, quantidades, rendimento e preparo juntos. Não pergunte ingrediente a ingrediente.',\n 'Insumo que não existir no catálogo: mande mesmo assim em `name` — ele volta marcado para o usuário escolher ou cadastrar.',\n].join(' ')\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { CrudListView, PermissionGate, QuickActionsButton, askAI, useAgentSurface } from '@fayz-ai/admin'\nimport { useDataChanged, useTranslation } from '@fayz-ai/core'\nimport type { EntityDef, PluginQuickAction } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { InventoryCurrency } from '../context'\nimport type { Product, Recipe, RecipeIngredient } from '../types'\nimport { CMV_ALERT_THRESHOLD, cmvPercent, isCmvHigh, recipeCost } from '../lib/recipe-cost'\nimport { RECIPE_SURFACE_INSTRUCTIONS } from '../lib/agent-tools'\nimport { AlertTriangle } from 'lucide-react'\n\n// ---------------------------------------------------------------------------\n// \"Which menu items still lack a ficha técnica?\" — the question this screen\n// actually answers, which is why it is driven from PRODUCTS and not from the\n// recipes that happen to exist. A sellable product with no recipe is a row too.\n// ---------------------------------------------------------------------------\n\ninterface RecipeRow {\n /** Recipe id, or `product:<id>` for a menu item with no ficha yet. */\n id: string\n recipeId?: string\n productId?: string\n productName: string\n /** Shown under the product when the ficha is named something else. */\n recipeName?: string\n ingredientCount: number\n yieldLabel: string\n prepLabel: string\n cost: number | null\n salePrice?: number\n cmv: number | null\n missing: boolean\n}\n\n/** A menu item: something the tenant sells, whether or not it is typed as such. */\nfunction isSellable(product: Product): boolean {\n return product.productType === 'sale' || (product.salePrice ?? 0) > 0\n}\n\nfunction buildRecipeEntity(t: (key: string, params?: Record<string, string>) => string, currency: InventoryCurrency): EntityDef {\n const money = (value: number | null | undefined) =>\n value == null ? '—' : formatCurrency(value, currency)\n\n return {\n name: t('inventory.recipes.entity'),\n namePlural: t('inventory.recipes.title'),\n icon: 'BookOpen',\n displayField: 'productName',\n fields: [\n {\n key: 'productName', label: t('inventory.recipes.colProduct'), type: 'text', searchable: true,\n renderCell: (_v, row: any) => (\n <div>\n <p className=\"font-medium\">{row.productName}</p>\n {row.missing\n ? <span className=\"mt-0.5 inline-flex items-center rounded-full bg-warning-soft px-2 py-0.5 text-[10px] font-medium text-warning-soft-foreground\">{t('inventory.recipes.noSheet')}</span>\n : row.recipeName && row.recipeName !== row.productName\n ? <p className=\"text-xs text-muted-foreground\">{row.recipeName}</p>\n : null}\n </div>\n ),\n },\n {\n key: 'ingredientCount', label: t('inventory.recipes.colIngredients'), type: 'number',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums\">{row.missing ? '—' : row.ingredientCount}</span>\n ),\n },\n {\n key: 'yieldLabel', label: t('inventory.recipes.colYield'), type: 'text',\n renderCell: (_v, row: any) => <span className=\"text-xs text-muted-foreground\">{row.yieldLabel || '—'}</span>,\n },\n {\n key: 'prepLabel', label: t('inventory.recipes.colPrep'), type: 'text',\n renderCell: (_v, row: any) => <span className=\"text-xs text-muted-foreground\">{row.prepLabel || '—'}</span>,\n },\n {\n key: 'cost', label: t('inventory.recipes.colCost'), type: 'currency',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums text-muted-foreground\">{money(row.cost)}</span>\n ),\n },\n {\n key: 'salePrice', label: t('inventory.recipes.colSale'), type: 'currency',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums\">{money(row.salePrice ?? null)}</span>\n ),\n },\n {\n key: 'cmv', label: t('inventory.recipes.colCmv'), type: 'number',\n renderCell: (_v, row: any) => (\n row.cmv == null\n ? <span className=\"block text-right text-muted-foreground\">—</span>\n : <span className={`block text-right tabular-nums font-medium ${isCmvHigh(row.cmv) ? 'text-destructive' : 'text-success'}`}>\n {row.cmv.toFixed(1)}%\n </span>\n ),\n },\n ],\n }\n}\n\nexport function RecipesView({ onNew, onView, onNewForProduct }: {\n onNew?: () => void\n onView?: (id: string) => void\n /** Starts a ficha for a menu item that has none. */\n onNewForProduct?: (productId: string) => void\n}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [recipes, setRecipes] = useState<Recipe[]>([])\n const [lines, setLines] = useState<RecipeIngredient[]>([])\n const [products, setProducts] = useState<Product[]>([])\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [loadError, setLoadError] = useState('')\n const [search, setSearch] = useState('')\n\n // A menu is menu-sized; one page is the whole answer and beats a query per row.\n const load = useCallback(async (): Promise<Recipe[]> => {\n try {\n const [recipeList, allLines, productPage] = await Promise.all([\n provider.getRecipes(),\n provider.getAllRecipeIngredients(),\n provider.getProducts({ pageSize: 500 }),\n ])\n setRecipes(recipeList)\n setLines(allLines)\n setProducts(productPage.data)\n setLoadError('')\n return recipeList\n } catch (error) {\n setLoadError(error instanceof Error ? error.message : String(error))\n return []\n } finally {\n setLoadedOnce(true)\n }\n }, [provider])\n\n useEffect(() => { void load() }, [load])\n\n // The assistant's write is a server-plane RPC, so nothing local knows it\n // happened — the data bus is how this screen learns, and landing on the new\n // recipe is what makes \"criar com IA\" end somewhere the user can read.\n const knownRecipeIds = useRef<Set<string>>(new Set())\n useEffect(() => { knownRecipeIds.current = new Set(recipes.map((r) => r.id)) }, [recipes])\n\n useDataChanged({}, () => {\n void (async () => {\n const before = knownRecipeIds.current\n const after = await load()\n const created = after.find((r) => !before.has(r.id))\n if (created && onView) onView(created.id)\n })()\n })\n\n const rows = useMemo<RecipeRow[]>(() => {\n const linesByRecipe = new Map<string, RecipeIngredient[]>()\n for (const line of lines) {\n const bucket = linesByRecipe.get(line.recipeId)\n if (bucket) bucket.push(line)\n else linesByRecipe.set(line.recipeId, [line])\n }\n const productById = new Map(products.map((p) => [p.id, p]))\n\n const built: RecipeRow[] = recipes.map((recipe) => {\n const own = linesByRecipe.get(recipe.id) ?? []\n const cost = recipeCost(own)\n const product = recipe.productId ? productById.get(recipe.productId) : undefined\n const salePrice = recipe.productSalePrice ?? product?.salePrice\n return {\n id: recipe.id,\n recipeId: recipe.id,\n productId: recipe.productId,\n productName: recipe.productName ?? product?.name ?? recipe.name,\n recipeName: recipe.name,\n ingredientCount: own.length || recipe.ingredientCount || 0,\n yieldLabel: recipe.yieldQuantity ? `${recipe.yieldQuantity}${recipe.yieldUnitName ? ` ${recipe.yieldUnitName}` : ''}` : '',\n prepLabel: recipe.preparationTimeMinutes != null ? `${recipe.preparationTimeMinutes} min` : '',\n cost,\n salePrice,\n cmv: cmvPercent(cost, salePrice),\n missing: false,\n } as RecipeRow\n })\n\n const covered = new Set(recipes.map((r) => r.productId).filter(Boolean) as string[])\n for (const product of products) {\n if (!isSellable(product) || covered.has(product.id)) continue\n built.push({\n id: `product:${product.id}`,\n productId: product.id,\n productName: product.name,\n ingredientCount: 0,\n yieldLabel: '',\n prepLabel: '',\n cost: null,\n salePrice: product.salePrice,\n cmv: null,\n missing: true,\n })\n }\n\n // Missing fichas first — they are the reason to open this screen.\n return built.sort((a, b) =>\n a.missing === b.missing ? a.productName.localeCompare(b.productName) : a.missing ? -1 : 1)\n }, [recipes, lines, products])\n\n const visibleRows = useMemo(() => {\n const term = search.trim().toLowerCase()\n return term ? rows.filter((r) => r.productName.toLowerCase().includes(term)) : rows\n }, [rows, search])\n\n const entity = useMemo(() => buildRecipeEntity(t, currency), [t, currency])\n\n // The model needs real ids and real costs, not a guess at the catalogue.\n const surfaceState = useRef({ rows, products })\n surfaceState.current = { rows, products }\n const surface = useMemo(() => ({\n id: 'inventory.recipes',\n pluginId: 'inventory',\n role: 'finance' as const,\n instructions: RECIPE_SURFACE_INSTRUCTIONS,\n describe: () => {\n const { rows: current, products: catalogue } = surfaceState.current\n return {\n title: 'Fichas técnicas',\n state: {\n ingredients: catalogue\n .filter((p) => !isSellable(p) || (p.costPrice ?? 0) > 0)\n .slice(0, 200)\n .map((p) => ({ id: p.id, name: p.name, unit: p.measurementUnitName, cost: p.costPrice })),\n menuItemsWithoutRecipe: current\n .filter((r) => r.missing)\n .map((r) => ({ productId: r.productId, name: r.productName, salePrice: r.salePrice })),\n recipes: current\n .filter((r) => !r.missing)\n .map((r) => ({ id: r.recipeId, product: r.productName, cost: r.cost, cmv: r.cmv })),\n cmvAlertThreshold: CMV_ALERT_THRESHOLD,\n },\n }\n },\n tools: [],\n }), [])\n useAgentSurface(surface)\n\n const createActions = useMemo<PluginQuickAction[]>(() => [\n {\n id: 'with-ai',\n label: t('assistant.askAI'),\n description: t('inventory.recipes.aiHint'),\n icon: 'WandSparkles',\n highlight: true,\n action: () => askAI({\n hint: t('inventory.recipes.askPlaceholder'),\n intro: {\n role: 'finance',\n persona: t('inventory.recipes.askPersona'),\n pitch: t('inventory.recipes.askPitch'),\n description: t('inventory.recipes.askDescription'),\n suggestions: [0, 1, 2].map((i) => ({ label: t(`inventory.recipes.askSuggestion.${i}`) })),\n },\n }),\n },\n ...(onNew ? [{\n id: 'by-hand',\n label: t('inventory.recipes.newByHand'),\n description: t('inventory.recipes.newByHandHint'),\n icon: 'SlidersHorizontal',\n action: onNew,\n } as PluginQuickAction] : []),\n ], [t, onNew])\n\n return loadError ? (\n <div className=\"flex min-h-[320px] flex-col items-center justify-center rounded-xl border-2 border-dashed border-destructive/30 bg-destructive/5 px-6 text-center\">\n <AlertTriangle className=\"mb-3 h-8 w-8 text-destructive\" />\n <p className=\"font-medium\">{t('inventory.recipes.loadFailed')}</p>\n <p className=\"mt-1 max-w-xl text-xs text-muted-foreground\">{loadError}</p>\n <button type=\"button\" onClick={() => void load()} className=\"mt-4 rounded-button border bg-card px-4 py-2 text-sm font-medium shadow-button hover:bg-muted\">\n {t('inventory.recipes.retry')}\n </button>\n </div>\n ) : (\n <CrudListView\n entityDef={entity}\n items={loadedOnce ? (visibleRows as unknown as Array<{ id: string }>) : null}\n total={visibleRows.length}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.recipes.searchPlaceholder')}\n headerActions={\n <PermissionGate feature=\"inventory\" action=\"create\">\n <QuickActionsButton variant=\"default\" label={t('inventory.recipes.newRecipe')} actions={createActions} />\n </PermissionGate>\n }\n onRowClick={(row) => {\n const target = row as unknown as RecipeRow\n if (target.missing && target.productId) onNewForProduct?.(target.productId)\n else if (target.recipeId) onView?.(target.recipeId)\n }}\n emptyMessage={t('inventory.recipes.noRecipes')}\n onRefresh={() => load().then(() => undefined)}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Plus, Trash2, GripVertical } from 'lucide-react'\nimport { useInventoryStore, useInventoryProvider } from '../context'\nimport { toast } from '@fayz-ai/ui'\nimport { SubpageHeader, useSaveBar } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SearchSelect } from '@fayz-ai/ui'\nimport { useLimitGuard, invalidateLimit } from '@fayz-ai/admin'\nimport type { CreateRecipeIngredientInput } from '../types'\n\ninterface FormIngredient {\n _id: string\n productId: string\n productName: string\n quantity: number\n unitId: string\n unitName: string\n notes: string\n}\n\nlet fid = 1\nfunction nextId() { return `ri${fid++}` }\n\nexport function RecipeFormView({ onSaved, productId: initialProductId }: {\n onSaved?: (id?: string) => void\n /** Menu item this ficha is for, when the list started it from a missing row. */\n productId?: string\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const createRecipe = useInventoryStore((s) => s.createRecipe)\n const guardRecipes = useLimitGuard('recipes')\n\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [productId, setProductId] = useState(initialProductId ?? '')\n const [productName, setProductName] = useState('')\n\n // Named by the product it produces — the ficha the row was asking for.\n useEffect(() => {\n if (!initialProductId) return\n let active = true\n void provider.getProductById(initialProductId).then((product) => {\n if (!active || !product) return\n setProductId(product.id)\n setProductName(product.name)\n setName((current) => current || product.name)\n })\n return () => { active = false }\n }, [initialProductId, provider])\n\n const [yieldQuantity, setYieldQuantity] = useState(1)\n const [prepTime, setPrepTime] = useState('')\n const [instructions, setInstructions] = useState('')\n const [ingredients, setIngredients] = useState<FormIngredient[]>([])\n const [saving, setSaving] = useState(false)\n\n function addIngredient() {\n setIngredients([...ingredients, { _id: nextId(), productId: '', productName: '', quantity: 1, unitId: '', unitName: '', notes: '' }])\n }\n\n function updateIngredient(id: string, data: Partial<FormIngredient>) {\n setIngredients(ingredients.map((ing) => ing._id === id ? { ...ing, ...data } : ing))\n }\n\n function removeIngredient(id: string) {\n setIngredients(ingredients.filter((ing) => ing._id !== id))\n }\n\n async function handleSave() {\n if (!name.trim() || !productId || ingredients.length === 0) { toast.error(t('common.formIncomplete')); return }\n // Plan quantity guard (client-side, before the provider call). Opens the\n // global UpgradeModal and aborts when the plan's recipe cap is reached.\n if ((await guardRecipes()) === 'blocked') return\n setSaving(true)\n try {\n const recipe = await createRecipe({\n name,\n description: description || undefined,\n productId,\n yieldQuantity,\n preparationTimeMinutes: prepTime ? parseInt(prepTime) : undefined,\n instructions: instructions || undefined,\n ingredients: ingredients.filter((i) => i.productId).map((i, idx) => ({\n productId: i.productId,\n quantity: i.quantity,\n unitId: i.unitId || undefined,\n displayOrder: idx,\n notes: i.notes || undefined,\n })),\n })\n invalidateLimit('recipes')\n onSaved?.(recipe.id)\n } finally { setSaving(false) }\n }\n\n const dirty = !!(name || description || productId || prepTime || instructions || ingredients.length > 0 || yieldQuantity !== 1)\n useSaveBar({\n dirty,\n saving,\n onSave: () => { void handleSave() },\n onDiscard: () => onSaved?.(),\n saveLabel: t('inventory.recipeForm.saveRecipe'),\n })\n\n async function searchProducts(query: string) {\n const result = await provider.getProducts({ search: query, pageSize: 10 })\n return result.data.map((p) => ({ id: p.id, label: p.name, subtitle: p.sku ?? p.productType, data: p }))\n }\n\n async function quickCreateProduct(name: string, type: 'ingredient' | 'sale' = 'ingredient') {\n try {\n const product = await provider.createProduct({ name, productType: type })\n toast.success(`Product \"${name}\" created`)\n return product\n } catch {\n toast.error('Failed to create product')\n return null\n }\n }\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader\n title={t('inventory.recipeForm.newRecipe')}\n subtitle={t('inventory.recipeForm.subtitle')}\n onBack={() => onSaved?.()}\n parentLabel={t('inventory.nav.recipes')}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n {/* Left: Recipe details */}\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <h3 className=\"text-sm font-semibold\">{t('inventory.recipeForm.recipeDetails')}</h3>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.recipeName')} *</label>\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inventory.recipeForm.recipeNamePlaceholder')} autoFocus className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.description')}</label>\n <textarea value={description} onChange={(e) => setDescription(e.target.value)} rows={2} placeholder={t('inventory.recipeForm.descriptionPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n\n <SearchSelect\n label={`${t('inventory.recipeForm.produces')} *`}\n value={productId}\n displayValue={productName}\n onChange={(id, opt) => { setProductId(id); setProductName(opt?.label ?? '') }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchProduct')}\n allowCreate\n createLabel={t('inventory.recipeForm.createProduct')}\n onCreate={async (q) => {\n const p = await quickCreateProduct(q, 'sale')\n if (p) { setProductId(p.id); setProductName(p.name) }\n }}\n />\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.yieldQuantity')}</label>\n <input type=\"number\" min={0.01} step={0.01} value={yieldQuantity} onChange={(e) => setYieldQuantity(Number(e.target.value) || 1)} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.prepTime')}</label>\n <input type=\"number\" min={0} value={prepTime} onChange={(e) => setPrepTime(e.target.value)} placeholder=\"—\" className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.instructions')}</label>\n <textarea value={instructions} onChange={(e) => setInstructions(e.target.value)} rows={4} placeholder={t('inventory.recipeForm.instructionsPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n </div>\n\n {/* Right: Ingredients */}\n <div className=\"lg:col-span-2 rounded-card border bg-card shadow-sm overflow-hidden flex flex-col\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b\">\n <h3 className=\"text-sm font-semibold\">{t('inventory.recipeForm.ingredients')}</h3>\n <button onClick={addIngredient} className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors\">\n <Plus className=\"h-3 w-3\" /> {t('inventory.recipeForm.addIngredient')}\n </button>\n </div>\n\n <div className=\"flex-1\">\n {ingredients.length === 0 ? (\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('inventory.recipeForm.noIngredients')}</p>\n <button onClick={addIngredient} className=\"text-xs text-primary hover:underline mt-1\">{t('inventory.recipeForm.addFirstIngredient')}</button>\n </div>\n ) : (\n <div className=\"divide-y\">\n {/* Header */}\n <div className=\"grid grid-cols-12 gap-2 px-4 py-2 text-[10px] font-medium text-muted-foreground uppercase tracking-wider bg-muted/20\">\n <div className=\"col-span-5\">{t('inventory.recipeForm.ingredient')}</div>\n <div className=\"col-span-2\">{t('inventory.recipeForm.quantity')}</div>\n <div className=\"col-span-4\">{t('inventory.recipeForm.notes')}</div>\n <div className=\"col-span-1\" />\n </div>\n {ingredients.map((ing, idx) => (\n <div key={ing._id} className=\"grid grid-cols-12 gap-2 px-4 py-2.5 items-center group\">\n <div className=\"col-span-5\">\n <SearchSelect\n value={ing.productId}\n displayValue={ing.productName}\n onChange={(id, opt) => updateIngredient(ing._id, { productId: id, productName: opt?.label ?? '' })}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchIngredient')}\n allowCreate\n createLabel={t('inventory.recipeForm.createIngredient')}\n onCreate={async (q) => {\n const p = await quickCreateProduct(q, 'ingredient')\n if (p) updateIngredient(ing._id, { productId: p.id, productName: p.name })\n }}\n />\n </div>\n <div className=\"col-span-2\">\n <input\n type=\"number\"\n min={0.01}\n step={0.01}\n value={ing.quantity}\n onChange={(e) => updateIngredient(ing._id, { quantity: Number(e.target.value) || 0 })}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div className=\"col-span-4\">\n <input\n type=\"text\"\n value={ing.notes}\n onChange={(e) => updateIngredient(ing._id, { notes: e.target.value })}\n placeholder={t('inventory.recipeForm.notesPlaceholder')}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div className=\"col-span-1 flex justify-end\">\n <button onClick={() => removeIngredient(ing._id)} className=\"p-1 text-muted-foreground opacity-0 group-hover:opacity-100 hover:text-destructive transition-all\">\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n {ingredients.length > 0 && (\n <div className=\"px-4 py-3 border-t bg-muted/20 text-xs text-muted-foreground\">\n {t('inventory.recipeForm.ingredientsConfigured', { configured: String(ingredients.filter((i) => i.productId).length), total: String(ingredients.length) })}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { AlertTriangle } from 'lucide-react'\nimport { SearchSelect, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { Product, Recipe, RecipeGaps } from '../types'\n\n/**\n * What the assistant proposed and could not match to the catalogue, offered\n * back for the user to pick or create. Without this the AI path dead-ends on\n * \"she mentioned bacon and it is not in the recipe\" — the recovery loop is what\n * made the legacy feature usable.\n */\nexport function RecipeGapsPanel({ recipe, gaps, onResolved }: {\n recipe: Recipe\n gaps: RecipeGaps\n onResolved: () => void | Promise<void>\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [busy, setBusy] = useState(false)\n\n const unmatched = gaps.unmatchedIngredients ?? []\n if (unmatched.length === 0 && !gaps.productHint) return null\n\n async function searchProducts(query: string) {\n const result = await provider.getProducts({ search: query, pageSize: 10 })\n return result.data.map((p) => ({ id: p.id, label: p.name, subtitle: p.sku ?? p.productType, data: p }))\n }\n\n async function quickCreate(name: string, productType: 'ingredient' | 'sale'): Promise<Product | null> {\n try {\n return await provider.createProduct({ name, productType })\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.createFailed'), { description: err?.message })\n return null\n }\n }\n\n function remainingGaps(index: number): RecipeGaps {\n return { ...gaps, unmatchedIngredients: unmatched.filter((_, i) => i !== index) }\n }\n\n async function linkIngredient(index: number, productId: string) {\n const gap = unmatched[index]\n setBusy(true)\n try {\n await provider.addRecipeIngredient(recipe.id, {\n productId,\n quantity: Number(gap?.quantity) > 0 ? Number(gap.quantity) : 1,\n notes: gap?.notes,\n })\n await provider.updateRecipe(recipe.id, { metadata: remainingGaps(index) as Record<string, unknown> })\n await onResolved()\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.linkFailed'), { description: err?.message })\n } finally {\n setBusy(false)\n }\n }\n\n async function linkProduct(productId: string) {\n setBusy(true)\n try {\n const { productHint: _dropped, ...rest } = gaps\n await provider.updateRecipe(recipe.id, { productId, metadata: rest as Record<string, unknown> })\n await onResolved()\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.linkFailed'), { description: err?.message })\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div className=\"rounded-card border border-warning/40 bg-warning/5 p-4 space-y-3\">\n <div className=\"flex items-start gap-2\">\n <AlertTriangle className=\"h-4 w-4 text-warning shrink-0 mt-px\" />\n <div>\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.recipeGaps.title')}</h3>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.recipeGaps.description')}</p>\n </div>\n </div>\n\n <div className={`space-y-2 ${busy ? 'opacity-60 pointer-events-none' : ''}`}>\n {gaps.productHint && (\n <div className=\"grid gap-2 sm:grid-cols-2 items-center\">\n <p className=\"text-xs\">\n <span className=\"text-muted-foreground\">{t('inventory.recipeGaps.produces')}</span>{' '}\n <strong className=\"text-foreground\">{gaps.productHint}</strong>\n </p>\n <SearchSelect\n value=\"\"\n onChange={(id) => { if (id) void linkProduct(id) }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchProduct')}\n allowCreate\n createLabel={t('inventory.recipeForm.createProduct')}\n onCreate={async (q) => {\n const p = await quickCreate(q, 'sale')\n if (p) await linkProduct(p.id)\n }}\n />\n </div>\n )}\n\n {unmatched.map((gap, index) => (\n <div key={`${gap.name}-${index}`} className=\"grid gap-2 sm:grid-cols-2 items-center\">\n <p className=\"text-xs\">\n <strong className=\"text-foreground\">{gap.name || t('inventory.recipeGaps.unnamed')}</strong>\n {Number(gap.quantity) > 0 && <span className=\"text-muted-foreground\"> · {gap.quantity}</span>}\n {gap.notes && <span className=\"text-muted-foreground\"> · {gap.notes}</span>}\n </p>\n <SearchSelect\n value=\"\"\n onChange={(id) => { if (id) void linkIngredient(index, id) }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchIngredient')}\n allowCreate\n createLabel={t('inventory.recipeForm.createIngredient')}\n onCreate={async (q) => {\n const p = await quickCreate(q, 'ingredient')\n if (p) await linkIngredient(index, p.id)\n }}\n />\n </div>\n ))}\n </div>\n </div>\n )\n}\n","import React, { useEffect, useMemo, useState } from 'react'\nimport { AlertTriangle, BookOpen, Clock, Coins, Layers, Package } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { DataTable, SubpageHeader } from '@fayz-ai/ui'\nimport type { Recipe, RecipeGaps, RecipeIngredient } from '../types'\nimport { CMV_ALERT_THRESHOLD, cmvPercent, ingredientUnitCost, isCmvHigh, recipeCost } from '../lib/recipe-cost'\nimport { RecipeGapsPanel } from '../components/RecipeGapsPanel'\n\n/** What the assistant could not resolve, as the RPC stored it. */\nfunction readGaps(recipe: Recipe | null): RecipeGaps {\n const meta = recipe?.metadata as RecipeGaps | undefined\n return {\n unmatchedIngredients: Array.isArray(meta?.unmatchedIngredients) ? meta!.unmatchedIngredients : undefined,\n productHint: typeof meta?.productHint === 'string' ? meta.productHint : undefined,\n }\n}\n\nfunction DetailSkeleton() {\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-12 w-12 rounded-xl bg-muted/40 animate-pulse\" />\n <div className=\"space-y-2 flex-1\">\n <div className=\"h-5 w-40 rounded bg-muted/40 animate-pulse\" />\n <div className=\"h-3 w-24 rounded bg-muted/30 animate-pulse\" />\n </div>\n </div>\n <div className=\"rounded-xl border divide-y\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"h-3 w-20 rounded bg-muted/30 animate-pulse\" />\n <div className=\"flex-1\" />\n <div className=\"h-3 w-16 rounded bg-muted/40 animate-pulse\" />\n </div>\n ))}\n </div>\n <div className=\"rounded-xl border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => (\n <div key={i} className=\"flex items-center gap-3\">\n <div className=\"h-3.5 w-6 rounded bg-muted/30 animate-pulse\" />\n <div className=\"h-3.5 flex-1 rounded bg-muted/30 animate-pulse\" />\n <div className=\"h-3.5 w-12 rounded bg-muted/40 animate-pulse\" />\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport function RecipeDetailView({ recipeId, onBack }: { recipeId: string; onBack: () => void }) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n const [recipe, setRecipe] = useState<Recipe | null>(null)\n const [ingredients, setIngredients] = useState<RecipeIngredient[]>([])\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n\n const load = React.useCallback(async () => {\n try {\n const [r, ings] = await Promise.all([\n provider.getRecipeById(recipeId),\n provider.getRecipeIngredients(recipeId),\n ])\n setRecipe(r)\n setIngredients(ings.sort((a, b) => a.displayOrder - b.displayOrder))\n setLoadError('')\n } catch (error) {\n setLoadError(error instanceof Error ? error.message : String(error))\n }\n }, [recipeId, provider])\n\n useEffect(() => {\n setLoading(true)\n void load().finally(() => setLoading(false))\n }, [load])\n\n const totalCost = useMemo(() => recipeCost(ingredients), [ingredients])\n const cmv = useMemo(() => cmvPercent(totalCost, recipe?.productSalePrice), [totalCost, recipe?.productSalePrice])\n const gaps = useMemo(() => readGaps(recipe), [recipe])\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={t('inventory.recipeDetail.loading')}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n />\n <DetailSkeleton />\n </div>\n )\n }\n\n if (loadError) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.recipeDetail.loadFailed')} icon=\"BookOpen\" onBack={onBack} parentLabel={t('inventory.nav.recipes')} />\n <div className=\"flex flex-col items-center justify-center rounded-xl border-2 border-dashed border-destructive/30 bg-destructive/5 px-6 py-16 text-center\">\n <AlertTriangle className=\"mb-3 h-8 w-8 text-destructive\" />\n <p className=\"font-medium\">{t('inventory.recipeDetail.loadFailed')}</p>\n <p className=\"mt-1 max-w-xl text-xs text-muted-foreground\">{loadError}</p>\n <button type=\"button\" onClick={() => { setLoading(true); void load().finally(() => setLoading(false)) }} className=\"mt-4 rounded-button border bg-card px-4 py-2 text-sm font-medium shadow-button hover:bg-muted\">\n {t('inventory.recipeDetail.retry')}\n </button>\n </div>\n </div>\n )\n }\n\n if (!recipe) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={t('inventory.recipeDetail.notFound')}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n />\n <div className=\"flex flex-col items-center justify-center py-16 text-center rounded-lg border-2 border-dashed border-muted\">\n <BookOpen className=\"h-8 w-8 text-muted-foreground/30 mb-2\" />\n <p className=\"text-sm text-muted-foreground\">{t('inventory.recipeDetail.notFound')}</p>\n <button onClick={onBack} className=\"text-xs text-primary hover:underline mt-1\">{t('inventory.recipeDetail.backToList')}</button>\n </div>\n </div>\n )\n }\n\n // A ficha whose ingredients carry no notes wastes a column on a row of dashes,\n // and the table is already wide enough to scroll on a laptop.\n const anyNotes = ingredients.some((i) => (i.notes ?? '').trim().length > 0)\n\n const ingredientColumns: ColumnDef<RecipeIngredient, any>[] = [\n {\n id: 'index', header: '#',\n cell: ({ row }) => <span className=\"text-xs text-muted-foreground\">{row.index + 1}</span>,\n },\n {\n accessorKey: 'productName', header: t('inventory.recipeDetail.ingredient'),\n cell: ({ getValue }) => <span className=\"font-medium\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.quantity')}</span>,\n cell: ({ getValue }) => <span className=\"block text-right tabular-nums\">{getValue() as number}</span>,\n },\n {\n accessorKey: 'unitName', header: t('inventory.recipeDetail.unit'),\n cell: ({ getValue }) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n ...(anyNotes ? [{\n accessorKey: 'notes', header: t('inventory.recipeDetail.notes'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n }] : []),\n {\n id: 'unitCost', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.unitCost')}</span>,\n cell: ({ row }) => (\n <span className=\"block text-right text-muted-foreground tabular-nums\">\n {formatCurrency(ingredientUnitCost(row.original.costBasis), currency)}\n </span>\n ),\n },\n {\n id: 'cost', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.cost')}</span>,\n cell: ({ row }) => (\n <span className=\"block text-right font-medium tabular-nums\">\n {formatCurrency(ingredientUnitCost(row.original.costBasis) * (row.original.quantity || 0), currency)}\n </span>\n ),\n },\n ]\n\n return (\n <div className=\"space-y-6\">\n {/* O mesmo cabeçalho de subpágina de todas as outras telas: o título, o\n caminho de volta e o estado à direita. O herói desenhado à mão que\n vivia aqui repetia o nome logo abaixo do rastro e escolhia a própria\n altura — duas gramáticas de topo dentro do mesmo app. */}\n <SubpageHeader\n title={recipe.name}\n subtitle={recipe.description}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n actions={\n recipe.isActive ? (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-success\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-success\" /> {t('inventory.recipeDetail.active')}\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-muted-foreground/50\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-muted-foreground/30\" /> {t('inventory.recipeDetail.inactive')}\n </span>\n )\n }\n />\n\n <RecipeGapsPanel recipe={recipe} gaps={gaps} onResolved={load} />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n {/* Left, and wide: the ingredients ARE the recipe. The list that gets\n read is the one that gets the room — it was squeezed into a third of\n the page while four numbers took the other two. */}\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-semibold text-foreground mb-2\">{t('inventory.recipeDetail.ingredientsTitle')}</h3>\n {ingredients.length === 0 ? (\n <div className=\"rounded-xl border p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.recipeDetail.noIngredients')}</p>\n </div>\n ) : (\n <DataTable columns={ingredientColumns} data={ingredients} variant=\"card\" />\n )}\n </div>\n\n {/* Right: the facts about the recipe, beside the list they describe. */}\n <div className=\"space-y-4\">\n {/* Metrics */}\n <div className=\"rounded-xl border divide-y\">\n {recipe.productName && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.produces')}</span>\n <span className=\"text-sm font-medium\">{recipe.productName}</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Layers className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.yield')}</span>\n <span className=\"text-sm font-medium\">{recipe.yieldQuantity}{recipe.yieldUnitName ? ` ${recipe.yieldUnitName}` : ''}</span>\n </div>\n {recipe.preparationTimeMinutes != null && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Clock className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.prepTime')}</span>\n <span className=\"text-sm font-medium\">{recipe.preparationTimeMinutes} min</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Layers className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.ingredientCount')}</span>\n <span className=\"text-sm font-medium\">{ingredients.length}</span>\n </div>\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.totalCost')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(totalCost, currency)}</span>\n </div>\n {recipe.yieldQuantity > 1 && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.costPerYield')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(totalCost / recipe.yieldQuantity, currency)}</span>\n </div>\n )}\n {recipe.productSalePrice != null && recipe.productSalePrice > 0 && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.salePrice')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(recipe.productSalePrice, currency)}</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.cmv')}</span>\n {cmv == null ? (\n <span className=\"text-xs text-muted-foreground\">{t('inventory.recipeDetail.cmvUnknown')}</span>\n ) : (\n <span className={`text-sm font-medium tabular-nums ${isCmvHigh(cmv) ? 'text-destructive' : 'text-success'}`}>\n {cmv.toFixed(1)}%\n </span>\n )}\n </div>\n </div>\n\n {isCmvHigh(cmv) && (\n <p className=\"flex items-start gap-1.5 text-[11px] text-destructive\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0 mt-px\" />\n {t('inventory.recipeDetail.cmvHigh', { threshold: String(CMV_ALERT_THRESHOLD) })}\n </p>\n )}\n\n {/* Instructions */}\n {recipe.instructions && (\n <div>\n <h3 className=\"text-sm font-semibold text-foreground mb-1\">{t('inventory.recipeDetail.instructions')}</h3>\n <div className=\"rounded-card border bg-card shadow-sm px-4 py-3\">\n <p className=\"text-xs text-muted-foreground whitespace-pre-wrap leading-relaxed\">{recipe.instructions}</p>\n </div>\n </div>\n )}\n\n {/* Dates */}\n <div className=\"flex items-center gap-4 text-[10px] text-muted-foreground/50\">\n <span>{t('inventory.recipeDetail.created')} {recipe.createdAt?.slice(0, 10)}</span>\n <span>{t('inventory.recipeDetail.updated')} {recipe.updatedAt?.slice(0, 10)}</span>\n </div>\n </div>\n\n </div>\n </div>\n )\n}\n","import React from 'react'\nimport { SettingsGroup, ToggleRow, useTenantPluginSettings } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\n\n// Per-tenant defaults = the values that used to be hardcoded here. Persisted +\n// re-hydrated per tenant; behavioural consumption is a follow-up.\nconst INVENTORY_DEFAULTS = {\n lowStockAlerts: true,\n requireReason: true,\n autoDeduct: false,\n requireSku: false,\n allowNegative: false,\n lowStockEmail: false,\n expiryWarnings: true,\n}\n\nexport function InventoryGeneralSettings() {\n const t = useTranslation()\n const s = useTenantPluginSettings('inventory', INVENTORY_DEFAULTS)\n return (\n <div className=\"space-y-4\">\n <SettingsGroup title={t('inventory.settings.stockManagement')} description={t('inventory.settings.stockManagementDesc')}>\n <ToggleRow label={t('inventory.settings.lowStockAlerts')} description={t('inventory.settings.lowStockAlertsDesc')} checked={s.get('lowStockAlerts')} onChange={(v) => s.set('lowStockAlerts', v)} />\n <ToggleRow label={t('inventory.settings.requireReason')} description={t('inventory.settings.requireReasonDesc')} checked={s.get('requireReason')} onChange={(v) => s.set('requireReason', v)} />\n <ToggleRow label={t('inventory.settings.autoDeduct')} description={t('inventory.settings.autoDeductDesc')} checked={s.get('autoDeduct')} onChange={(v) => s.set('autoDeduct', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('inventory.settings.products')} description={t('inventory.settings.productsDesc')}>\n <ToggleRow label={t('inventory.settings.requireSku')} description={t('inventory.settings.requireSkuDesc')} checked={s.get('requireSku')} onChange={(v) => s.set('requireSku', v)} />\n <ToggleRow label={t('inventory.settings.allowNegative')} description={t('inventory.settings.allowNegativeDesc')} checked={s.get('allowNegative')} onChange={(v) => s.set('allowNegative', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('inventory.settings.notifications')} description={t('inventory.settings.notificationsDesc')}>\n <ToggleRow label={t('inventory.settings.lowStockEmail')} description={t('inventory.settings.lowStockEmailDesc')} checked={s.get('lowStockEmail')} onChange={(v) => s.set('lowStockEmail', v)} />\n <ToggleRow label={t('inventory.settings.expiryWarnings')} description={t('inventory.settings.expiryWarningsDesc')} checked={s.get('expiryWarnings')} onChange={(v) => s.set('expiryWarnings', v)} />\n </SettingsGroup>\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { Package, Ruler, MapPin, ChevronRight, Check, Loader2 } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { Button } from '@fayz-ai/ui'\n\nconst STEPS = [\n { id: 'welcome', icon: Package, titleKey: 'inventory.onboarding.welcome', descKey: 'inventory.onboarding.description' },\n { id: 'units', icon: Ruler, titleKey: 'inventory.onboarding.units.title', descKey: 'inventory.onboarding.units.description' },\n { id: 'locations', icon: MapPin, titleKey: 'inventory.onboarding.locations.title', descKey: 'inventory.onboarding.locations.description' },\n]\n\nexport function InventoryOnboarding({ onComplete }: { onComplete: () => void | Promise<void> }) {\n const t = useTranslation()\n const [step, setStep] = useState(0)\n const [preparing, setPreparing] = useState(false)\n const [error, setError] = useState('')\n const current = STEPS[step]\n const isLast = step === STEPS.length - 1\n const Icon = current.icon\n\n async function complete() {\n if (preparing) return\n setPreparing(true)\n setError('')\n try {\n await onComplete()\n } catch {\n setError(t('inventory.onboarding.setupError'))\n } finally {\n setPreparing(false)\n }\n }\n\n return (\n <div className=\"flex items-center justify-center py-12\">\n <div className=\"w-full max-w-lg\">\n <div className=\"flex items-center gap-1 mb-8\">\n {STEPS.map((_, i) => (\n <div key={i} className={`h-1 flex-1 rounded-full transition-colors ${i <= step ? 'bg-primary' : 'bg-muted'}`} />\n ))}\n </div>\n <div className=\"rounded-card border bg-card p-8 text-center space-y-6 shadow-sm\">\n <div className=\"flex justify-center\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-primary/10\">\n <Icon className=\"h-8 w-8 text-primary\" />\n </div>\n </div>\n <div>\n <h2 className=\"text-xl font-bold\">{t(current.titleKey)}</h2>\n <p className=\"text-sm text-muted-foreground mt-2 max-w-sm mx-auto\">{t(current.descKey)}</p>\n </div>\n <div className=\"flex items-center justify-center gap-3 pt-2\">\n {step > 0 && (\n <Button variant=\"outline\" size=\"lg\" onClick={() => setStep(step - 1)}>{t('common.back')}</Button>\n )}\n {isLast ? (\n <Button variant=\"default\" size=\"lg\" onClick={() => void complete()} disabled={preparing}>\n {preparing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Check className=\"h-4 w-4\" />}\n {preparing ? t('inventory.onboarding.preparing') : t('inventory.onboarding.start')}\n </Button>\n ) : (\n <Button variant=\"default\" size=\"lg\" onClick={() => setStep(step + 1)}>\n {step === 0 ? t('inventory.onboarding.getStarted') : t('common.continue')} <ChevronRight className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n {step === 0 && (\n <button onClick={() => void complete()} disabled={preparing} className=\"text-xs text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50\">\n {t('inventory.onboarding.skip')}\n </button>\n )}\n {error && <p role=\"alert\" className=\"text-sm text-destructive\">{error}</p>}\n </div>\n </div>\n </div>\n )\n}\n","import React, { useState, useMemo } from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ModulePage, PageTransition, type ModuleNavItem } from '@fayz-ai/ui'\nimport { InventoryContextProvider, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport type { InventoryUIState } from '../store'\nimport type { PluginRegistryDef, PluginQuickAction } from '@fayz-ai/core'\nimport { useModuleNavigation, ModuleActionBar, createViewRouter, PluginSettingsPanel } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { DashboardView } from './DashboardView'\nimport { ProductListView } from './ProductListView'\nimport { ProductCrudForm } from './ProductCrudForm'\nimport { ProductDetailView } from './ProductDetailView'\nimport { StockMovementView } from './StockMovementView'\nimport { MovementHistoryView } from './MovementHistoryView'\nimport { StockCountsView } from './StockCountsView'\nimport { StockCountFormView } from './StockCountFormView'\nimport { StockCountSessionView } from './StockCountSessionView'\nimport { RecipesView } from './RecipesView'\nimport { RecipeFormView } from './RecipeFormView'\nimport { RecipeDetailView } from './RecipeDetailView'\nimport { InventoryGeneralSettings } from '../components/InventoryGeneralSettings'\nimport { InventoryOnboarding } from '../components/InventoryOnboarding'\n\nfunction buildNav(config: ResolvedInventoryConfig, view: string, navigate: (v: string) => void, t: (key: string) => string): ModuleNavItem[] {\n const items: ModuleNavItem[] = [\n { id: 'dashboard', label: t('inventory.nav.dashboard'), icon: 'BarChart3', active: view === 'dashboard', onClick: () => navigate('dashboard') },\n ...(config.modules.products ? [{\n id: 'products', label: t('inventory.nav.products'), icon: 'Package', active: view.startsWith('products'),\n children: [\n { id: 'products-new', label: t('inventory.nav.new'), active: view === 'products-new', onClick: () => navigate('products-new') },\n { id: 'products-list', label: t('inventory.nav.list'), active: view === 'products-list' || view.startsWith('products-detail:') || view.startsWith('products-stock:'), onClick: () => navigate('products-list') },\n ],\n } as ModuleNavItem] : []),\n {\n id: 'stock', label: t('inventory.nav.stock'), icon: 'ArrowUpCircle',\n children: [\n { id: 'stock-entry', label: t('inventory.nav.entry'), active: view === 'stock-entry', onClick: () => navigate('stock-entry') },\n { id: 'stock-exit', label: t('inventory.nav.exit'), active: view === 'stock-exit', onClick: () => navigate('stock-exit') },\n // Before History on purpose: the parent tab flattens to the LAST child,\n // and \"Stock\" has always landed on History.\n { id: 'stock-counts', label: t('inventory.nav.counts'), active: view === 'stock-counts' || view.startsWith('stock-counts'), onClick: () => navigate('stock-counts') },\n { id: 'stock-history', label: t('inventory.nav.history'), active: view === 'stock-history', onClick: () => navigate('stock-history') },\n ],\n },\n ]\n\n if (config.modules.recipes) {\n items.push({\n id: 'recipes', label: config.labels.recipes, icon: 'BookOpen',\n children: [\n { id: 'recipes-list', label: config.labels.recipesList, active: view === 'recipes-list' || view.startsWith('recipes-detail:'), onClick: () => navigate('recipes-list') },\n { id: 'recipes-new', label: config.labels.recipesNew, active: view === 'recipes-new', onClick: () => navigate('recipes-new') },\n ],\n })\n }\n\n return items\n}\n\nexport function InventoryPage({ config, provider, store, registries }: {\n config: ResolvedInventoryConfig\n provider: InventoryDataProvider\n store: StoreApi<InventoryUIState>\n registries?: PluginRegistryDef[]\n}) {\n const t = useTranslation()\n const { view, direction, navigate } = useModuleNavigation('/inventory', {\n dashboard: 0,\n 'products-list': 0, 'products-new': 1, 'products-detail': 1,\n 'stock-entry': 1, 'stock-exit': 1, 'stock-history': 0, 'stock-counts': 0, 'stock-counts-new': 1,\n 'recipes-list': 0, 'recipes-new': 1, 'recipes-detail': 1,\n settings: 1,\n }, 'dashboard')\n\n const [onboardingComplete, setOnboardingComplete] = useState(() => {\n try { return localStorage.getItem('saas-core:inventory-onboarded') === 'true' } catch { return false }\n })\n\n const isSettings = view === 'settings'\n const isSummary = view === 'dashboard' || view === ''\n const nav = buildNav(config, view, navigate, t)\n\n const completeOnboarding = React.useCallback(async () => {\n await provider.ensureReferenceData?.()\n setOnboardingComplete(true)\n try { localStorage.setItem('saas-core:inventory-onboarded', 'true') } catch {}\n }, [provider])\n\n const quickActions = useMemo<PluginQuickAction[]>(() => {\n const actions: PluginQuickAction[] = [\n // Dropped with the catalogue module: offering \"new product\" while the\n // screen is gone would dead-end the user.\n ...(config.modules.products ? [{\n id: 'new-product',\n label: t('inventory.quickActions.newProduct'),\n icon: 'Package',\n description: t('inventory.quickActions.newProductDesc'),\n action: () => navigate('products-new'),\n } as PluginQuickAction] : []),\n {\n id: 'stock-entry',\n label: t('inventory.quickActions.stockEntry'),\n icon: 'ArrowUpRight',\n description: t('inventory.quickActions.stockEntryDesc'),\n action: () => navigate('stock-entry'),\n },\n {\n id: 'stock-exit',\n label: t('inventory.quickActions.stockExit'),\n icon: 'ArrowDownRight',\n description: t('inventory.quickActions.stockExitDesc'),\n action: () => navigate('stock-exit'),\n },\n ]\n return actions\n }, [])\n\n if (!onboardingComplete) {\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <InventoryOnboarding onComplete={completeOnboarding} />\n </InventoryContextProvider>\n )\n }\n\n if (isSettings && registries && registries.length > 0) {\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <PageTransition transitionKey=\"settings\" direction={direction}>\n <div style={{ padding: '24px' }}>\n <div style={{ marginBottom: '16px' }}>\n <h1 style={{ fontSize: '20px', fontWeight: 600, margin: 0 }}>{t('inventory.settingsPage.title')}</h1>\n <p style={{ color: 'var(--muted-foreground, #6b7280)', margin: '4px 0 0', fontSize: '14px' }}>\n {t('inventory.settingsPage.subtitle')}\n </p>\n </div>\n <PluginSettingsPanel\n title={t('inventory.settingsPage.title')}\n generalSettings={<InventoryGeneralSettings />}\n registries={registries}\n hostPluginId=\"inventory\"\n routeBase=\"/inventory/settings\"\n />\n </div>\n </PageTransition>\n </InventoryContextProvider>\n )\n }\n\n const renderView = createViewRouter([\n // Routes go with the module, not just the nav entry: leaving them mounted\n // keeps a second product form reachable by URL.\n ...(config.modules.products ? [\n { id: 'products', render: () => <ProductListView onNew={() => navigate('products-new')} onOpen={(id: string) => navigate(`products-detail:${id}`)} /> },\n { id: 'products-list', render: () => <ProductListView onNew={() => navigate('products-new')} onOpen={(id: string) => navigate(`products-detail:${id}`)} /> },\n { id: 'products-new', render: () => <ProductCrudForm onSaved={() => navigate('products-list')} /> },\n { id: 'products-edit', render: ({ id }: { id?: string }) => <ProductCrudForm editId={id!} onSaved={() => navigate(`products-detail:${id}`)} /> },\n { id: 'products-detail', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n // The tab writes `/products/<id>/stock` into the URL, so that link has to\n // come back to the same page with the tab open.\n { id: 'products-stock', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} initialTab=\"stock\" onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n ] : []),\n { id: 'stock-entry', render: () => <StockMovementView defaultType=\"entry\" onSaved={() => navigate('stock-history')} /> },\n { id: 'stock-exit', render: () => <StockMovementView defaultType=\"exit\" onSaved={() => navigate('stock-history')} /> },\n { id: 'stock-history', render: () => <MovementHistoryView onViewDetail={(id) => navigate(`stock-detail:${id}`)} onNew={() => navigate('stock-entry')} onNewExit={() => navigate('stock-exit')} /> },\n { id: 'stock-detail', render: ({ id }) => {\n const movement = store.getState().movements.find((m) => m.id === id)\n return movement\n ? <StockMovementView defaultType={movement.movementType} viewMovement={movement} onSaved={() => navigate('stock-history')} />\n : <MovementHistoryView onViewDetail={(mid) => navigate(`stock-detail:${mid}`)} />\n } },\n // One route id for both: `/inventory/stock/counts/<uuid>` parses back as\n // `stock-counts:<id>`, not `stock-counts-detail:<id>`.\n { id: 'stock-counts', render: ({ id }: { id?: string }) => id\n ? <StockCountSessionView sessionId={id} onBack={() => navigate('stock-counts')} />\n : <StockCountsView onNew={() => navigate('stock-counts-new')} onOpen={(sid) => navigate(`stock-counts:${sid}`)} /> },\n { id: 'stock-counts-new', render: () => <StockCountFormView onOpened={(sid) => navigate(`stock-counts:${sid}`)} onCancel={() => navigate('stock-counts')} /> },\n { id: 'recipes', render: () => <RecipesView onNew={() => navigate('recipes-new')} onView={(id) => navigate(`recipes-detail:${id}`)} onNewForProduct={(pid) => navigate(`recipes-new:${pid}`)} /> },\n { id: 'recipes-list', render: () => <RecipesView onNew={() => navigate('recipes-new')} onView={(id) => navigate(`recipes-detail:${id}`)} onNewForProduct={(pid) => navigate(`recipes-new:${pid}`)} /> },\n { id: 'recipes-new', render: ({ id }: { id?: string }) => <RecipeFormView productId={id} onSaved={(rid) => rid ? navigate(`recipes-detail:${rid}`) : navigate('recipes-list')} /> },\n { id: 'recipes-detail', render: ({ id }) => <RecipeDetailView recipeId={id!} onBack={() => navigate('recipes-list')} /> },\n { id: 'dashboard', render: () => <DashboardView /> },\n ], 'dashboard')\n\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <ModulePage\n title={config.labels.pageTitle}\n subtitle={config.labels.pageSubtitle}\n nav={nav}\n showHeader={isSummary}\n viewKey={view}\n direction={direction}\n headerAction={\n <ModuleActionBar\n quickActions={quickActions}\n settingsPath={registries && registries.length > 0 ? '/settings/inventory' : undefined}\n />\n }\n >\n {renderView(view)}\n </ModulePage>\n </InventoryContextProvider>\n )\n}\n","import React, { useEffect } from 'react'\nimport { ArrowUpRight, ArrowDownRight } from 'lucide-react'\nimport type { StoreApi } from 'zustand'\nimport type { DashboardWidgetDef } from '@fayz-ai/core'\nimport { useTranslation } from '@fayz-ai/core'\nimport {\n KpiCard, Card, CardHeader, CardTitle, CardContent,\n defineKpiWidget, defineCustomWidget,\n} from '@fayz-ai/ui'\nimport { InventoryContextProvider, useInventoryConfig, useInventoryStore, formatCurrency, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport type { InventoryUIState } from '../store'\n\nfunction useEnsureSummary() {\n const fetchSummary = useInventoryStore((s) => s.fetchSummary)\n useEffect(() => { void fetchSummary() }, [])\n}\n\nfunction StockValueKpi() {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return (\n <KpiCard label={t('inventory.dashboard.stockValue')} icon=\"BarChart3\"\n value={formatCurrency(summary?.totalStockValue ?? 0, currency)} sub={t('inventory.dashboard.totalValue')} />\n )\n}\n\nfunction TotalProductsKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.totalProducts')} icon=\"Package\" value={String(summary?.totalProducts ?? 0)} sub={t('inventory.dashboard.activeItems')} />\n}\n\nfunction LowStockKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.lowStock')} icon=\"AlertTriangle\" value={String(summary?.lowStockCount ?? 0)} sub={t('inventory.dashboard.belowMinimum')} />\n}\n\nfunction OutOfStockKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.outOfStock')} icon=\"TrendingDown\" value={String(summary?.outOfStockCount ?? 0)} sub={t('inventory.dashboard.needRestocking')} />\n}\n\nfunction RecentActivityPanel() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return (\n <Card>\n <CardHeader><CardTitle>{t('inventory.dashboard.recentActivity')}</CardTitle></CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-4 text-sm\">\n <div className=\"flex items-center gap-1.5\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-success\" />\n <span className=\"text-muted-foreground\">{t('inventory.dashboard.entries')}</span>\n <span className=\"font-medium\">{summary?.movementsByType?.entry ?? 0}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <ArrowDownRight className=\"h-3.5 w-3.5 text-destructive\" />\n <span className=\"text-muted-foreground\">{t('inventory.dashboard.exits')}</span>\n <span className=\"font-medium\">{summary?.movementsByType?.exit ?? 0}</span>\n </div>\n </div>\n <p className=\"mt-2 text-xs text-muted-foreground\">{t('inventory.dashboard.last7Days')}</p>\n </CardContent>\n </Card>\n )\n}\n\nexport function createInventoryDashboardWidgets(ctx: {\n config: ResolvedInventoryConfig\n provider: InventoryDataProvider\n store: StoreApi<InventoryUIState>\n}): DashboardWidgetDef[] {\n const withCtx = (Inner: React.ComponentType): React.ComponentType<unknown> => {\n const Wrapped = () => (\n <InventoryContextProvider config={ctx.config} provider={ctx.provider} store={ctx.store}>\n <Inner />\n </InventoryContextProvider>\n )\n Wrapped.displayName = `InventoryWidget(${Inner.displayName ?? Inner.name})`\n return Wrapped\n }\n\n return [\n // Stock value is inventory's headline KPI on the global home; the rest are\n // home-hidden by default (shown on the inventory plugin-home, addable via Customize).\n defineKpiWidget({ id: 'inventory.kpi.stock-value', title: 'inventory.dashboard.stockValue', domain: 'inventory', defaultOrder: 0, component: withCtx(StockValueKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.total-products', title: 'inventory.dashboard.totalProducts', domain: 'inventory', defaultOrder: 1, defaultVisible: false, component: withCtx(TotalProductsKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.low-stock', title: 'inventory.dashboard.lowStock', domain: 'inventory', defaultOrder: 2, defaultVisible: false, component: withCtx(LowStockKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.out-of-stock', title: 'inventory.dashboard.outOfStock', domain: 'inventory', defaultOrder: 3, defaultVisible: false, component: withCtx(OutOfStockKpi) }),\n defineCustomWidget({ id: 'inventory.panel.recent-activity', title: 'inventory.dashboard.recentActivity', domain: 'inventory', span: 2, defaultOrder: 10, surfaces: ['plugin-home'], component: withCtx(RecentActivityPanel) }),\n ]\n}\n","import type { InventoryDataProvider } from './types'\nimport type {\n Product, StockMovement, StockPosition, StockLocation, Supplier,\n Recipe, RecipeIngredient, RecipeGroup,\n StockCountSession, StockCountItem, ProductCategory,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput, CreateRecipeIngredientInput,\n OpenStockCountInput, CloseStockCountResult,\n ProductQuery, MovementQuery,\n PaginatedResult, InventorySummary, MovementType,\n} from '../types'\nimport { isDivergent } from '../lib/stock-count'\n\nlet nextId = 1\nfunction uid(): string { return String(nextId++) }\nfunction now(): string { return new Date().toISOString() }\nfunction today(): string { return new Date().toISOString().slice(0, 10) }\n\nfunction paginate<T>(items: T[], page?: number, pageSize?: number): PaginatedResult<T> {\n const p = page ?? 1\n const ps = pageSize ?? 50\n const start = (p - 1) * ps\n return { data: items.slice(start, start + ps), total: items.length }\n}\n\ninterface MockStore {\n products: Product[]\n movements: StockMovement[]\n positions: StockPosition[]\n locations: StockLocation[]\n suppliers: Supplier[]\n recipes: Recipe[]\n recipeIngredients: RecipeIngredient[]\n recipeGroups: RecipeGroup[]\n countSessions: StockCountSession[]\n countItems: StockCountItem[]\n}\n\nfunction createStore(): MockStore {\n return {\n products: [],\n movements: [],\n positions: [],\n locations: [\n { id: uid(), name: 'Main Storage', description: 'Primary storage area', isActive: true, tenantId: 'mock-tenant', createdAt: now(), updatedAt: now() },\n ],\n suppliers: [\n { id: uid(), name: 'Main Supplier' },\n ],\n recipes: [],\n recipeIngredients: [],\n recipeGroups: [],\n countSessions: [],\n countItems: [],\n }\n}\n\nexport function createMockInventoryProvider(): InventoryDataProvider {\n const store = createStore()\n const tenantId = 'mock-tenant'\n\n /** The produced product's name and price, as the Supabase embed resolves them. */\n function withProduct(recipe: Recipe): Recipe {\n const product = store.products.find((p) => p.id === recipe.productId)\n return { ...recipe, productName: product?.name ?? recipe.productName, productSalePrice: product?.salePrice }\n }\n\n function withCostBasis(ing: RecipeIngredient): RecipeIngredient {\n const product = store.products.find((p) => p.id === ing.productId)\n if (!product) return ing\n return {\n ...ing,\n productName: product.name ?? ing.productName,\n costBasis: {\n cost: product.costPrice ?? 0,\n conversionFactor: product.conversionFactor,\n purchaseUnitId: product.purchaseUnitId,\n },\n }\n }\n\n /** Same slot key the Supabase provider uses: product + location + batch + expiry. */\n /** Mirrors the supabase provider: `set` makes the slot BE `amount`. Returns the effective delta. */\n function applyPositionDelta(\n input: Pick<CreateStockMovementInput, 'productId' | 'unitCost' | 'batchNumber' | 'expirationDate'>,\n locationId: string,\n amount: number,\n mode: 'add' | 'set' = 'add',\n ): number {\n const slot = store.positions.find((p) =>\n p.productId === input.productId &&\n p.stockLocationId === locationId &&\n (p.batchNumber ?? null) === (input.batchNumber ?? null) &&\n (p.expirationDate ?? null) === (input.expirationDate ?? null)\n )\n if (slot) {\n const current = slot.quantity\n slot.quantity = mode === 'set' ? amount : current + amount\n slot.unitCost = input.unitCost ?? slot.unitCost\n slot.updatedAt = now()\n return slot.quantity - current\n }\n store.positions.push({\n id: uid(),\n productId: input.productId,\n quantity: amount,\n unitCost: input.unitCost ?? 0,\n stockLocationId: locationId,\n stockLocationName: store.locations.find((l) => l.id === locationId)?.name,\n batchNumber: input.batchNumber,\n expirationDate: input.expirationDate,\n tenantId,\n createdAt: now(),\n })\n return amount\n }\n\n const provider: InventoryDataProvider = {\n async ensureReferenceData(): Promise<void> {\n // The mock store is born with its reference data already available.\n },\n\n // --- Products ---\n async getProducts(query: ProductQuery): Promise<PaginatedResult<Product>> {\n let results = [...store.products]\n if (query.productType) results = results.filter((p) => p.productType === query.productType)\n if (query.categoryId) results = results.filter((p) => p.categoryId === query.categoryId)\n if (query.isActive !== undefined) results = results.filter((p) => p.isActive === query.isActive)\n if (query.lowStockOnly) results = results.filter((p) => p.currentQuantity <= p.minQuantity)\n if (query.search) {\n const s = query.search.toLowerCase()\n results = results.filter((p) => p.name.toLowerCase().includes(s) || p.sku?.toLowerCase().includes(s) || p.barcode?.includes(s))\n }\n results.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return paginate(results, query.page, query.pageSize)\n },\n\n async getProductById(id: string): Promise<Product | null> {\n return store.products.find((p) => p.id === id) ?? null\n },\n\n async createProduct(input: CreateProductInput): Promise<Product> {\n const product: Product = {\n id: uid(),\n name: input.name,\n description: input.description,\n sku: input.sku,\n barcode: input.barcode,\n brand: input.brand,\n categoryId: input.categoryId,\n productType: input.productType,\n purpose: input.purpose,\n currentQuantity: 0,\n minQuantity: input.minQuantity ?? 0,\n maxQuantity: input.maxQuantity,\n costPrice: input.costPrice ?? 0,\n salePrice: input.salePrice,\n measurementUnitId: input.measurementUnitId,\n purchaseUnitId: input.purchaseUnitId,\n conversionFactor: input.conversionFactor ?? 1,\n isActive: true,\n supplierId: input.supplierId,\n defaultLocationId: input.defaultLocationId,\n imageUrl: input.imageUrl,\n metadata: input.metadata,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.products.push(product)\n return product\n },\n\n async updateProduct(id: string, data: Partial<Product>): Promise<Product> {\n const product = store.products.find((p) => p.id === id)\n if (!product) throw new Error(`Product ${id} not found`)\n Object.assign(product, data, { updatedAt: now() })\n return product\n },\n\n async uploadProductImage(productId: string, file: File): Promise<string> {\n const product = store.products.find((p) => p.id === productId)\n if (!product) throw new Error(`Product ${productId} not found`)\n const url = typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'\n ? URL.createObjectURL(file)\n : `mock://inventory-images/${tenantId}/products/${productId}/${encodeURIComponent(file.name)}`\n product.imageUrl = url\n product.updatedAt = now()\n return url\n },\n\n // --- Stock Movements ---\n async getMovements(query: MovementQuery): Promise<PaginatedResult<StockMovement>> {\n let results = [...store.movements]\n if (query.productId) results = results.filter((m) => m.productId === query.productId)\n if (query.movementType) {\n const types = Array.isArray(query.movementType) ? query.movementType : [query.movementType]\n results = results.filter((m) => types.includes(m.movementType))\n }\n if (query.stockLocationId) results = results.filter((m) => m.stockLocationId === query.stockLocationId)\n if (query.dateRange) {\n results = results.filter((m) => m.movementDate >= query.dateRange!.from && m.movementDate <= query.dateRange!.to)\n }\n if (query.search) {\n const s = query.search.toLowerCase()\n results = results.filter((m) => m.productName?.toLowerCase().includes(s) || m.notes?.toLowerCase().includes(s))\n }\n results.sort((a, b) => b.movementDate.localeCompare(a.movementDate))\n return paginate(results, query.page, query.pageSize)\n },\n\n async createMovement(input: CreateStockMovementInput): Promise<StockMovement> {\n const product = store.products.find((p) => p.id === input.productId)\n const location = input.stockLocationId ? store.locations.find((l) => l.id === input.stockLocationId) : undefined\n const unitCost = input.unitCost ?? product?.costPrice ?? 0\n\n const movement: StockMovement = {\n id: uid(),\n productId: input.productId,\n productName: product?.name,\n quantity: input.quantity,\n movementType: input.movementType,\n unitCost,\n totalCost: unitCost * input.quantity,\n stockLocationId: input.stockLocationId,\n stockLocationName: location?.name,\n destinationLocationId: input.destinationLocationId,\n supplierId: input.supplierId,\n supplierName: store.suppliers.find((s) => s.id === input.supplierId)?.name,\n documentNumber: input.documentNumber,\n reason: input.reason,\n notes: input.notes,\n batchNumber: input.batchNumber,\n expirationDate: input.expirationDate,\n movementDate: input.movementDate ?? today(),\n tenantId,\n createdAt: now(),\n }\n store.movements.push(movement)\n\n let stockDelta =\n input.movementType === 'entry' ? input.quantity\n : input.movementType === 'exit' || input.movementType === 'loss' ? -input.quantity\n : 0\n\n if (input.stockLocationId) {\n const slot = { ...input, unitCost }\n // `adjustment` declares effect 'set': the quantity is the counted truth,\n // not a delta. It used to be subtracted like an exit.\n const mode = input.movementType === 'adjustment' ? 'set' : 'add'\n const amount = mode === 'set'\n ? input.quantity\n : (input.movementType === 'entry' ? input.quantity : -input.quantity)\n const applied = applyPositionDelta(slot, input.stockLocationId, amount, mode)\n if (input.movementType === 'adjustment') stockDelta = applied\n\n if (input.movementType === 'transfer' && input.destinationLocationId) {\n applyPositionDelta(slot, input.destinationLocationId, input.quantity)\n stockDelta = 0\n }\n } else if (input.movementType === 'adjustment') {\n stockDelta = input.quantity - (product?.currentQuantity ?? 0)\n }\n\n if (product) {\n product.currentQuantity += stockDelta\n product.updatedAt = now()\n }\n\n return movement\n },\n\n async reverseMovement(movementId: string): Promise<void> {\n const index = store.movements.findIndex((m) => m.id === movementId)\n if (index === -1) throw new Error(`Movement ${movementId} not found`)\n const movement = store.movements[index]\n\n const product = store.products.find((p) => p.id === movement.productId)\n if (product) {\n if (movement.movementType === 'entry') product.currentQuantity -= movement.quantity\n else if (movement.movementType === 'exit' || movement.movementType === 'loss') product.currentQuantity += movement.quantity\n product.updatedAt = now()\n }\n\n if (movement.stockLocationId) {\n const slot = {\n productId: movement.productId,\n unitCost: movement.unitCost,\n batchNumber: movement.batchNumber,\n expirationDate: movement.expirationDate,\n }\n applyPositionDelta(slot, movement.stockLocationId, movement.movementType === 'entry' ? -movement.quantity : movement.quantity)\n if (movement.movementType === 'transfer' && movement.destinationLocationId) {\n applyPositionDelta(slot, movement.destinationLocationId, -movement.quantity)\n }\n }\n\n store.movements.splice(index, 1)\n },\n\n // --- Stock Positions ---\n async getPositions(productId: string): Promise<StockPosition[]> {\n return store.positions.filter((p) => p.productId === productId)\n },\n\n // --- Stock Locations ---\n async getLocations(): Promise<StockLocation[]> {\n return store.locations.filter((l) => l.isActive)\n },\n\n async createLocation(data): Promise<StockLocation> {\n const location: StockLocation = {\n id: uid(),\n name: data.name,\n description: data.description,\n isActive: true,\n unitId: data.unitId,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.locations.push(location)\n return location\n },\n\n // --- Suppliers ---\n async getSuppliers(): Promise<Supplier[]> {\n return store.suppliers\n },\n\n // --- Categories ---\n async getCategories(): Promise<ProductCategory[]> {\n const seen = new Map<string, ProductCategory>()\n for (const product of store.products) {\n if (!product.categoryId || seen.has(product.categoryId)) continue\n seen.set(product.categoryId, {\n id: product.categoryId,\n name: product.categoryName ?? product.categoryId,\n isActive: true,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n })\n }\n return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name))\n },\n\n // --- Stock counts ---\n async getCountSessions(): Promise<StockCountSession[]> {\n return [...store.countSessions]\n .sort((a, b) => b.openedAt.localeCompare(a.openedAt))\n .map((session) => {\n const items = store.countItems.filter((i) => i.sessionId === session.id)\n return {\n ...session,\n itemCount: items.length,\n countedCount: items.filter((i) => i.countedQuantity !== undefined).length,\n divergentCount: items.filter(isDivergent).length,\n }\n })\n },\n\n async getCountSession(id: string): Promise<StockCountSession | null> {\n return store.countSessions.find((s) => s.id === id) ?? null\n },\n\n async getCountItems(sessionId: string): Promise<StockCountItem[]> {\n return store.countItems\n .filter((i) => i.sessionId === sessionId)\n .sort((a, b) => (a.productName ?? '').localeCompare(b.productName ?? ''))\n },\n\n async openCountSession(input: OpenStockCountInput): Promise<StockCountSession> {\n const location = store.locations.find((l) => l.id === input.stockLocationId)\n if (!location) throw new Error(`Stock location ${input.stockLocationId} not found`)\n\n const session: StockCountSession = {\n id: uid(),\n reference: input.reference?.trim() || undefined,\n status: 'open',\n stockLocationId: input.stockLocationId,\n stockLocationName: location.name,\n categoryId: input.categoryId,\n blind: input.blind ?? true,\n notes: input.notes,\n openedAt: now(),\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.countSessions.push(session)\n\n // Snapshot AT OPEN: what the system believes now, frozen on the line.\n for (const product of store.products) {\n if (!product.isActive || product.productType === 'asset') continue\n if (input.categoryId && product.categoryId !== input.categoryId) continue\n const slots = store.positions.filter(\n (p) => p.productId === product.id && p.stockLocationId === input.stockLocationId,\n )\n store.countItems.push({\n id: uid(),\n sessionId: session.id,\n productId: product.id,\n productName: product.name,\n productSku: product.sku,\n systemQuantity: slots.reduce((sum, p) => sum + (p.quantity ?? 0), 0),\n unitCost: slots[0]?.unitCost ?? product.costPrice ?? 0,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n })\n }\n return session\n },\n\n async saveCountEntry(itemId: string, quantity: number | null, notes?: string): Promise<StockCountItem> {\n const item = store.countItems.find((i) => i.id === itemId)\n if (!item) throw new Error(`Count item ${itemId} not found`)\n item.countedQuantity = quantity == null ? undefined : quantity\n item.countedAt = quantity == null ? undefined : now()\n if (notes !== undefined) item.notes = notes || undefined\n item.updatedAt = now()\n\n const session = store.countSessions.find((s) => s.id === item.sessionId)\n if (session && session.status === 'open') session.status = 'counting'\n return item\n },\n\n async closeCountSession(sessionId: string, reason?: string): Promise<CloseStockCountResult> {\n const session = store.countSessions.find((s) => s.id === sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n if (session.status === 'closed') {\n return { sessionId, adjustmentsCreated: 0, alreadyClosed: true }\n }\n if (session.status === 'cancelled') throw new Error('This count was cancelled')\n\n let emitted = 0\n for (const item of store.countItems) {\n if (item.sessionId !== sessionId) continue\n // Uncounted lines and lines that already adjusted are both skipped.\n if (!isDivergent(item) || item.movementId) continue\n const counted = item.countedQuantity as number\n const delta = counted - item.systemQuantity\n\n const movement: StockMovement = {\n id: uid(),\n productId: item.productId,\n productName: item.productName,\n quantity: counted,\n movementType: 'adjustment',\n unitCost: item.unitCost,\n totalCost: item.unitCost * counted,\n stockLocationId: session.stockLocationId,\n stockLocationName: session.stockLocationName,\n reason: reason || 'Stock count',\n movementDate: today(),\n metadata: {\n countSessionId: sessionId,\n countItemId: item.id,\n systemQuantity: item.systemQuantity,\n countedQuantity: counted,\n variance: delta,\n },\n tenantId,\n createdAt: now(),\n }\n store.movements.push(movement)\n item.movementId = movement.id\n item.updatedAt = now()\n\n applyPositionDelta({ productId: item.productId, unitCost: item.unitCost }, session.stockLocationId, delta)\n const product = store.products.find((p) => p.id === item.productId)\n if (product) {\n product.currentQuantity += delta\n product.updatedAt = now()\n }\n emitted += 1\n }\n\n session.status = 'closed'\n session.closedAt = now()\n session.updatedAt = now()\n return { sessionId, adjustmentsCreated: emitted, alreadyClosed: false }\n },\n\n async cancelCountSession(sessionId: string): Promise<StockCountSession> {\n const session = store.countSessions.find((s) => s.id === sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n if (session.status === 'closed') throw new Error('A closed count cannot be cancelled')\n session.status = 'cancelled'\n session.updatedAt = now()\n return session\n },\n\n // --- Recipes ---\n async getRecipes(): Promise<Recipe[]> {\n return store.recipes.filter((r) => r.isActive).map(withProduct)\n },\n\n async getRecipeById(id: string): Promise<Recipe | null> {\n const recipe = store.recipes.find((r) => r.id === id)\n return recipe ? withProduct(recipe) : null\n },\n\n async getRecipeIngredients(recipeId: string): Promise<RecipeIngredient[]> {\n return store.recipeIngredients\n .filter((ri) => ri.recipeId === recipeId)\n .sort((a, b) => a.displayOrder - b.displayOrder)\n .map(withCostBasis)\n },\n\n async getAllRecipeIngredients(): Promise<RecipeIngredient[]> {\n return store.recipeIngredients.map(withCostBasis)\n },\n\n async getRecipeGroups(recipeId: string): Promise<RecipeGroup[]> {\n return store.recipeGroups.filter((g) => g.recipeId === recipeId).sort((a, b) => a.displayOrder - b.displayOrder)\n },\n\n async createRecipe(input: CreateRecipeInput): Promise<Recipe> {\n const product = store.products.find((p) => p.id === input.productId)\n const recipeId = uid()\n const recipe: Recipe = {\n id: recipeId,\n name: input.name,\n description: input.description,\n productId: input.productId,\n productName: product?.name,\n yieldQuantity: input.yieldQuantity,\n yieldUnitId: input.yieldUnitId,\n preparationTimeMinutes: input.preparationTimeMinutes,\n instructions: input.instructions,\n isActive: true,\n ingredientCount: input.ingredients.length,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n // One active ficha per product. Re-saving used to leave the previous one\n // active too, and `consumeRecipeForSource` picks a single active recipe —\n // so a stale duplicate could be the one deciding a stock movement.\n for (const existing of store.recipes) {\n if (existing.id !== recipeId && existing.productId === input.productId && existing.isActive) {\n existing.isActive = false\n existing.updatedAt = now()\n }\n }\n store.recipes.push(recipe)\n\n for (const ing of input.ingredients) {\n const ingProduct = store.products.find((p) => p.id === ing.productId)\n store.recipeIngredients.push({\n id: uid(),\n recipeId,\n productId: ing.productId,\n productName: ingProduct?.name,\n quantity: ing.quantity,\n unitId: ing.unitId,\n displayOrder: ing.displayOrder ?? 0,\n notes: ing.notes,\n createdAt: now(),\n })\n }\n\n return recipe\n },\n\n async updateRecipe(id: string, patch: Partial<Recipe>): Promise<Recipe> {\n const recipe = store.recipes.find((r) => r.id === id)\n if (!recipe) throw new Error(`Recipe ${id} not found`)\n Object.assign(recipe, patch, { updatedAt: now() })\n return withProduct(recipe)\n },\n\n async addRecipeIngredient(recipeId: string, input: CreateRecipeIngredientInput): Promise<RecipeIngredient> {\n const product = store.products.find((p) => p.id === input.productId)\n const ingredient: RecipeIngredient = {\n id: uid(),\n recipeId,\n productId: input.productId,\n productName: product?.name,\n quantity: input.quantity,\n unitId: input.unitId,\n displayOrder: input.displayOrder ?? store.recipeIngredients.filter((i) => i.recipeId === recipeId).length,\n notes: input.notes,\n createdAt: now(),\n }\n store.recipeIngredients.push(ingredient)\n const recipe = store.recipes.find((r) => r.id === recipeId)\n if (recipe) recipe.ingredientCount = store.recipeIngredients.filter((i) => i.recipeId === recipeId).length\n return withCostBasis(ingredient)\n },\n\n // --- Summary ---\n async getSummary(): Promise<InventorySummary> {\n const active = store.products.filter((p) => p.isActive)\n const lowStock = active.filter((p) => p.currentQuantity <= p.minQuantity && p.currentQuantity > 0)\n const outOfStock = active.filter((p) => p.currentQuantity <= 0)\n const totalValue = active.reduce((sum, p) => sum + p.currentQuantity * p.costPrice, 0)\n\n const weekAgo = new Date()\n weekAgo.setDate(weekAgo.getDate() - 7)\n const weekAgoStr = weekAgo.toISOString().slice(0, 10)\n const recent = store.movements.filter((m) => m.movementDate >= weekAgoStr)\n\n const movementsByType: Record<MovementType, number> = { entry: 0, exit: 0, adjustment: 0, transfer: 0, loss: 0 }\n for (const m of recent) movementsByType[m.movementType]++\n\n return {\n totalProducts: active.length,\n lowStockCount: lowStock.length,\n outOfStockCount: outOfStock.length,\n totalStockValue: totalValue,\n recentMovementCount: recent.length,\n movementsByType,\n }\n },\n }\n\n return provider\n}\n","export const DEFAULT_MEASUREMENT_UNITS = [\n { name: 'Unit', abbreviation: 'un' },\n { name: 'Box', abbreviation: 'box' },\n { name: 'Kilogram', abbreviation: 'kg' },\n { name: 'Gram', abbreviation: 'g' },\n { name: 'Liter', abbreviation: 'L' },\n { name: 'Milliliter', abbreviation: 'mL' },\n] as const\n\nexport const DEFAULT_STOCK_LOCATION = {\n name: 'Main Storage',\n description: 'Primary storage area',\n} as const\n\nexport function getMissingMeasurementUnits(\n rows: Array<{ abbreviation?: string | null }>,\n): typeof DEFAULT_MEASUREMENT_UNITS[number][] {\n const existing = new Set(\n rows.map((row) => String(row.abbreviation ?? '').trim().toLocaleLowerCase()),\n )\n return DEFAULT_MEASUREMENT_UNITS.filter(\n (unit) => !existing.has(unit.abbreviation.toLocaleLowerCase()),\n )\n}\n\nexport function getDuplicateDefaultUnitIds(\n rows: Array<{ id: string; abbreviation?: string | null; created_at?: string | null }>,\n): string[] {\n const defaults = new Set(\n DEFAULT_MEASUREMENT_UNITS.map((unit) => unit.abbreviation.toLocaleLowerCase()),\n )\n const firstByAbbreviation = new Map<string, number>()\n const duplicates: string[] = []\n\n for (const row of [...rows].sort((a, b) =>\n String(a.created_at ?? '').localeCompare(String(b.created_at ?? '')) || a.id.localeCompare(b.id),\n )) {\n const abbreviation = String(row.abbreviation ?? '').trim().toLocaleLowerCase()\n if (!defaults.has(abbreviation)) continue\n const createdAt = row.created_at ? Date.parse(row.created_at) : Number.NaN\n const firstAt = firstByAbbreviation.get(abbreviation)\n if (firstAt === undefined) {\n if (Number.isFinite(createdAt)) firstByAbbreviation.set(abbreviation, createdAt)\n continue\n }\n // Delete only the near-simultaneous copy created by the former StrictMode\n // race. A same-abbreviation unit created independently later is user data.\n if (Number.isFinite(createdAt) && Math.abs(createdAt - firstAt) <= 60_000) duplicates.push(row.id)\n }\n\n return duplicates\n}\n\nexport function getDuplicateAutoCreatedLocationIds(\n rows: Array<{ id: string; name?: string | null; created_at?: string | null }>,\n): string[] {\n const defaults = rows\n .filter((row) => row.name === DEFAULT_STOCK_LOCATION.name && row.created_at)\n .sort((a, b) => String(a.created_at).localeCompare(String(b.created_at)) || a.id.localeCompare(b.id))\n const first = defaults[0]\n if (!first?.created_at) return []\n const firstAt = Date.parse(first.created_at)\n\n // Only collapse the near-simultaneous copies produced by the former\n // StrictMode race. Locations created independently at another time remain.\n return defaults.slice(1)\n .filter((row) => Math.abs(Date.parse(String(row.created_at)) - firstAt) <= 60_000)\n .map((row) => row.id)\n}\n","import type { InventoryDataProvider } from './types'\nimport type {\n Product, StockMovement, StockPosition, StockLocation, Supplier,\n Recipe, RecipeIngredient, RecipeGroup,\n StockCountSession, StockCountItem, ProductCategory,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput, CreateRecipeIngredientInput,\n OpenStockCountInput, CloseStockCountResult,\n ProductQuery, MovementQuery,\n PaginatedResult, InventorySummary, MovementType,\n} from '../types'\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { getInventoryTenantId } from '../lib/tenant'\nimport { T } from './tables'\nimport {\n DEFAULT_STOCK_LOCATION,\n getDuplicateAutoCreatedLocationIds,\n getDuplicateDefaultUnitIds,\n getMissingMeasurementUnits,\n} from './reference-data'\n\nconst referenceDataPromises = new Map<string, Promise<void>>()\n\nfunction getTenantId(): string | undefined {\n // Local override wins; else use the app's active tenant so writes pass RLS.\n return getInventoryTenantId() ?? getActiveTenantId()\n}\n\nfunction snakeToCamel(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n const camelKey = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())\n result[camelKey] = value\n }\n return result\n}\n\nfunction camelToSnake(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n if (key.startsWith('_')) continue\n const snakeKey = key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`)\n result[snakeKey] = value\n }\n return result\n}\n\n/** Embed alias for the 005 satellite — one round trip instead of an N+1. */\nconst PRODUCT_SELECT = `*, ${T.productDetails}(*)`\n\nfunction supabaseError(operation: string, error: { message?: string } | null | undefined): void {\n if (error) throw new Error(`${operation}: ${error.message ?? 'Supabase request failed'}`)\n}\n\n/**\n * Hydrate recipe products explicitly instead of relying on a PostgREST embed.\n *\n * Pools can briefly have a stale relationship cache after plugin migrations,\n * and an embedded `products(...)` select then makes the whole recipe query\n * fail. The old provider discarded that error and returned an empty list,\n * which looked exactly like a recipe that vanished after save.\n */\nasync function hydrateRecipeRows(pub: any, rows: Record<string, any>[]): Promise<Recipe[]> {\n const productIds = [...new Set(rows.map((row) => row.product_id).filter(Boolean))]\n const productsById = new Map<string, Record<string, any>>()\n if (productIds.length > 0) {\n const { data, error } = await pub.from('products').select('id, name, price').in('id', productIds)\n supabaseError('Could not read recipe products', error)\n for (const product of data ?? []) productsById.set(product.id, product)\n }\n return rows.map((row) => mapRecipeRow({ ...row, products: productsById.get(row.product_id) }))\n}\n\n/** Hydrate ingredient costing without a nested PostgREST relationship select. */\nasync function hydrateRecipeIngredientRows(\n pub: any,\n rows: Record<string, any>[],\n includeGroups: boolean,\n): Promise<RecipeIngredient[]> {\n const productIds = [...new Set(rows.map((row) => row.product_id).filter(Boolean))]\n const productsById = new Map<string, Record<string, any>>()\n const detailsByProductId = new Map<string, Record<string, any>>()\n const unitsById = new Map<string, Record<string, any>>()\n\n if (productIds.length > 0) {\n const [{ data: products, error: productsError }, { data: details, error: detailsError }] = await Promise.all([\n pub.from('products').select('id, name, cost').in('id', productIds),\n pub.from(T.productDetails).select('product_id, conversion_factor, measurement_unit_id, purchase_unit_id').in('product_id', productIds),\n ])\n supabaseError('Could not read recipe ingredient products', productsError)\n supabaseError('Could not read recipe ingredient details', detailsError)\n for (const product of products ?? []) productsById.set(product.id, product)\n for (const detail of details ?? []) detailsByProductId.set(detail.product_id, detail)\n\n const unitIds = [...new Set([\n ...rows.map((row) => row.unit_id),\n ...(details ?? []).map((detail: Record<string, any>) => detail.measurement_unit_id),\n ].filter(Boolean))]\n if (unitIds.length > 0) {\n const { data: units, error: unitsError } = await pub\n .from(T.measurementUnits)\n .select('id, name, abbreviation')\n .in('id', unitIds)\n supabaseError('Could not read recipe ingredient units', unitsError)\n for (const unit of units ?? []) unitsById.set(unit.id, unit)\n }\n }\n\n const groupsById = new Map<string, Record<string, any>>()\n if (includeGroups) {\n const groupIds = [...new Set(rows.map((row) => row.group_id).filter(Boolean))]\n if (groupIds.length > 0) {\n const { data, error } = await pub.from(T.recipeGroups).select('id, name').in('id', groupIds)\n supabaseError('Could not read recipe groups', error)\n for (const group of data ?? []) groupsById.set(group.id, group)\n }\n }\n\n return rows.map((row) => {\n const product = productsById.get(row.product_id)\n const details = detailsByProductId.get(row.product_id)\n const hydratedProduct = product\n ? { ...product, [T.productDetails]: details }\n : undefined\n const ingredient = mapRecipeIngredientRow({\n ...row,\n products: hydratedProduct,\n [T.recipeGroups]: groupsById.get(row.group_id),\n })\n const unitId = row.unit_id ?? details?.measurement_unit_id\n const unit = unitId ? unitsById.get(unitId) : undefined\n ingredient.unitId = unitId ?? ingredient.unitId\n ingredient.unitName = unit?.abbreviation ?? unit?.name ?? ingredient.unitName\n return ingredient\n })\n}\n\n/** PostgREST returns a one-to-one embed as an object or a single-element array. */\nfunction embedded(value: unknown): Record<string, any> | undefined {\n const one = Array.isArray(value) ? value[0] : value\n return one && typeof one === 'object' ? (one as Record<string, any>) : undefined\n}\n\n/** The row without its embeds — snakeToCamel would otherwise carry them through\n * under mangled keys (`plgInventoryRecipeGroups`). */\nfunction withoutEmbeds(row: Record<string, any>, keys: string[]): Record<string, any> {\n const copy = { ...row }\n for (const key of keys) delete copy[key]\n return copy\n}\n\nfunction mapRecipeRow(row: Record<string, any>): Recipe {\n const recipe = snakeToCamel(withoutEmbeds(row, ['products'])) as any\n const product = embedded(row.products)\n if (product) {\n recipe.productName = product.name ?? recipe.productName\n recipe.productSalePrice = product.price ?? undefined\n }\n return recipe as Recipe\n}\n\nfunction mapRecipeIngredientRow(row: Record<string, any>): RecipeIngredient {\n const ing = snakeToCamel(withoutEmbeds(row, ['products', T.recipeGroups])) as any\n const group = embedded(row[T.recipeGroups])\n if (group) ing.groupName = group.name\n const product = embedded(row.products)\n if (product) {\n const details = embedded(product[T.productDetails])\n ing.productName = product.name ?? ing.productName\n ing.costBasis = {\n cost: Number(product.cost) || 0,\n conversionFactor: details?.conversion_factor ?? undefined,\n purchaseUnitId: details?.purchase_unit_id ?? undefined,\n }\n }\n return ing as RecipeIngredient\n}\n\n/** A session carries where and what it counts, resolved for the list. */\nconst COUNT_SESSION_SELECT =\n `*, ${T.stockLocations}(name), ${T.productCategories}(name)`\n\nfunction mapCountSessionRow(row: Record<string, any>): StockCountSession {\n const session = snakeToCamel(\n withoutEmbeds(row, [T.stockLocations, T.productCategories]),\n ) as any\n session.stockLocationName = embedded(row[T.stockLocations])?.name\n session.categoryName = embedded(row[T.productCategories])?.name\n session.blind = row.blind ?? true\n return session as StockCountSession\n}\n\nfunction mapCountItemRow(row: Record<string, any>): StockCountItem {\n const item = snakeToCamel(withoutEmbeds(row, ['products'])) as any\n const product = embedded(row.products)\n if (product) {\n item.productName = product.name\n item.productSku = product.sku ?? undefined\n }\n item.systemQuantity = Number(row.system_quantity) || 0\n // NULL stays undefined: nobody counted this line, which is not zero.\n item.countedQuantity = row.counted_quantity == null ? undefined : Number(row.counted_quantity)\n item.unitCost = Number(row.unit_cost) || 0\n return item as StockCountItem\n}\n\n/**\n * Map a public.products row to our Product type.\n *\n * Products are the spine archetype, so anything inventory-specific lives either\n * in `metadata` (free-form attributes) or in plg_inventory_product_details (the\n * things that are foreign keys and need referential integrity).\n */\nfunction mapProductRow(row: Record<string, any>): Product {\n const meta = row.metadata ?? {}\n // PostgREST returns an embedded one-to-one as an object or a single-element\n // array depending on how it inferred the relationship.\n const rawDetails = row[T.productDetails]\n const d = (Array.isArray(rawDetails) ? rawDetails[0] : rawDetails) ?? {}\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n sku: row.sku,\n barcode: meta.barcode,\n brand: meta.brand,\n productType: meta.productType ?? 'sale',\n currentQuantity: row.stock ?? 0,\n minQuantity: row.min_stock ?? 0,\n maxQuantity: meta.maxQuantity,\n costPrice: row.cost ?? 0,\n salePrice: row.price,\n categoryId: d.category_id ?? undefined,\n measurementUnitId: d.measurement_unit_id ?? undefined,\n purchaseUnitId: d.purchase_unit_id ?? undefined,\n conversionFactor: d.conversion_factor ?? undefined,\n supplierId: d.supplier_id ?? undefined,\n defaultLocationId: d.default_location_id ?? undefined,\n purpose: d.purpose ?? undefined,\n isActive: row.is_active ?? true,\n imageUrl: row.image_url,\n metadata: meta,\n tenantId: row.tenant_id,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\n/** The satellite columns, or null when the caller touched none of them. */\nfunction productDetailsRow(\n input: Partial<CreateProductInput>,\n): Record<string, unknown> | null {\n const row: Record<string, unknown> = {}\n if (input.categoryId !== undefined) row.category_id = input.categoryId || null\n if (input.measurementUnitId !== undefined) row.measurement_unit_id = input.measurementUnitId || null\n if (input.purchaseUnitId !== undefined) row.purchase_unit_id = input.purchaseUnitId || null\n if (input.conversionFactor !== undefined) row.conversion_factor = input.conversionFactor ?? 1\n if (input.supplierId !== undefined) row.supplier_id = input.supplierId || null\n if (input.defaultLocationId !== undefined) row.default_location_id = input.defaultLocationId || null\n if (input.purpose !== undefined) row.purpose = input.purpose || null\n return Object.keys(row).length > 0 ? row : null\n}\n\n/**\n * Move one (product, location, batch, expiry) slot, and report how much the\n * on-hand total actually changed.\n *\n * `mode: 'add'` shifts the slot by `amount`; `mode: 'set'` makes the slot BE\n * `amount`. The distinction is the movement vocabulary's: an `adjustment`\n * declares `effect: 'set'` — it is the counted truth, not a delta — while entry\n * and exit are deltas. Returning the effective delta is what lets the caller\n * keep `products.stock` in step without re-reading the slot.\n *\n * The slot is identified by the full key of uq_..._slot (006), not just\n * product+location — before that index existed a product could hold several\n * rows per location and this read picked an arbitrary one. On the insert race\n * we retry once against the row the other writer just created; the unique index\n * is what makes that retry correct instead of producing a second row.\n */\nasync function applyPositionDelta(\n pub: any,\n tenantId: string | undefined,\n input: CreateStockMovementInput,\n locationId: string,\n amount: number,\n mode: 'add' | 'set' = 'add',\n): Promise<number> {\n const slot = (qb: any) => qb\n .eq('product_id', input.productId)\n .eq('stock_location_id', locationId)\n .is('batch_number', input.batchNumber ?? null)\n .is('expiration_date', input.expirationDate ?? null)\n\n const bump = async (): Promise<number | null> => {\n const { data: existing, error } = await slot(\n pub.from(T.stockPositions).select('id, quantity'),\n ).maybeSingle()\n if (error) throw new Error(error.message)\n if (!existing) return null\n const current = Number(existing.quantity) || 0\n const next = mode === 'set' ? amount : current + amount\n const { error: updateError } = await pub.from(T.stockPositions)\n .update({ quantity: next, unit_cost: input.unitCost ?? 0 })\n .eq('id', existing.id)\n if (updateError) throw new Error(updateError.message)\n return next - current\n }\n\n const bumped = await bump()\n if (bumped !== null) return bumped\n\n const { error: insertError } = await pub.from(T.stockPositions).insert({\n tenant_id: tenantId,\n product_id: input.productId,\n stock_location_id: locationId,\n quantity: amount,\n unit_cost: input.unitCost ?? 0,\n batch_number: input.batchNumber ?? null,\n expiration_date: input.expirationDate ?? null,\n })\n if (!insertError) return amount\n\n // 23505 = another writer created the slot between our read and our insert.\n if ((insertError as any).code === '23505') {\n const retried = await bump()\n if (retried !== null) return retried\n }\n throw new Error(insertError.message)\n}\n\nexport function createSupabaseInventoryProvider(): InventoryDataProvider {\n // Lazy resolution — Supabase client may not exist at factory time\n // but will be available when methods are called (after createSaasApp initializes it)\n function getClients() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return { core: supabase, pub: supabase }\n }\n\n const provider: InventoryDataProvider = {\n async ensureReferenceData(): Promise<void> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) return\n\n const running = referenceDataPromises.get(tenantId)\n if (running) return running\n\n const prepare = (async () => {\n // Onboarding used to claim these rows were ready while only writing a\n // localStorage flag. Fill only what is missing so existing tenant\n // customisations remain untouched and repeated mounts are harmless.\n const { data: units, error: unitsError } = await pub\n .from(T.measurementUnits)\n .select('id, abbreviation, created_at')\n .eq('tenant_id', tenantId)\n if (unitsError) throw new Error(unitsError.message)\n\n // React StrictMode exposed the old check-then-insert race by mounting\n // the form twice. Collapse only duplicate DEFAULT abbreviations and\n // keep the oldest row; custom units are never candidates for removal.\n const duplicateIds = getDuplicateDefaultUnitIds(units ?? [])\n if (duplicateIds.length > 0) {\n const { error } = await pub.from(T.measurementUnits).delete().in('id', duplicateIds)\n if (error) throw new Error(error.message)\n }\n\n const missing = getMissingMeasurementUnits(units ?? [])\n if (missing.length > 0) {\n const { error } = await pub.from(T.measurementUnits).insert(\n missing.map((unit) => ({ ...unit, tenant_id: tenantId, is_active: true })),\n )\n if (error) throw new Error(error.message)\n }\n\n // Keep the second onboarding promise true as well: stock movements and\n // the product form need at least one place to point at.\n const { data: locations, error: locationError } = await pub\n .from(T.stockLocations)\n .select('id, name, created_at')\n .eq('tenant_id', tenantId)\n if (locationError) throw new Error(locationError.message)\n\n const duplicateLocationIds = getDuplicateAutoCreatedLocationIds(locations ?? [])\n if (duplicateLocationIds.length > 0) {\n const { error } = await pub.from(T.stockLocations).delete().in('id', duplicateLocationIds)\n if (error) throw new Error(error.message)\n }\n\n if (!locations || locations.length === 0) {\n const { error } = await pub.from(T.stockLocations).insert({\n tenant_id: tenantId,\n ...DEFAULT_STOCK_LOCATION,\n is_active: true,\n })\n if (error) throw new Error(error.message)\n }\n })()\n\n referenceDataPromises.set(tenantId, prepare)\n try {\n await prepare\n } finally {\n if (referenceDataPromises.get(tenantId) === prepare) referenceDataPromises.delete(tenantId)\n }\n },\n\n // --- Products (public.products) ---\n async getProducts(query: ProductQuery): Promise<PaginatedResult<Product>> {\n const { core, pub } = getClients()\n // `!inner` only when filtering on a satellite column, so products without\n // a details row are not dropped from an unfiltered list.\n const select = query.categoryId ? `*, ${T.productDetails}!inner(*)` : PRODUCT_SELECT\n let qb = core.from('products').select(select, { count: 'exact' })\n if (query.search) qb = qb.ilike('name', `%${query.search}%`)\n // productType lives in the metadata JSON column → filter on metadata->>productType.\n if (query.productType) qb = qb.eq('metadata->>productType', query.productType)\n if (query.categoryId) qb = qb.eq(`${T.productDetails}.category_id`, query.categoryId)\n if (query.isActive !== undefined) qb = qb.eq('is_active', query.isActive)\n if (query.lowStockOnly) qb = qb.lte('stock', 0) // simplified\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 50\n qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order('created_at', { ascending: false })\n const { data, count } = await qb\n return { data: (data ?? []).map(mapProductRow), total: count ?? 0 }\n },\n\n async getProductById(id: string): Promise<Product | null> {\n const { core } = getClients()\n const { data } = await core.from('products').select(PRODUCT_SELECT).eq('id', id).single()\n return data ? mapProductRow(data) : null\n },\n\n async createProduct(input: CreateProductInput): Promise<Product> {\n const { core } = getClients()\n const tenantId = getTenantId()\n const row: Record<string, unknown> = {\n tenant_id: tenantId,\n name: input.name,\n description: input.description,\n sku: input.sku,\n price: input.salePrice ?? 0,\n cost: input.costPrice ?? 0,\n stock: 0,\n min_stock: input.minQuantity ?? 0,\n is_active: true,\n image_url: input.imageUrl,\n metadata: { productType: input.productType, barcode: input.barcode, brand: input.brand, maxQuantity: input.maxQuantity },\n }\n const { data, error } = await core.from('products').insert(row).select().single()\n if (error) throw new Error(error.message)\n\n const details = productDetailsRow(input)\n if (details) {\n const { error: detailsError } = await core.from(T.productDetails)\n .upsert({ ...details, product_id: data!.id, tenant_id: tenantId }, { onConflict: 'product_id' })\n if (detailsError) throw new Error(detailsError.message)\n }\n return (await provider.getProductById(data!.id)) ?? mapProductRow(data!)\n },\n\n async updateProduct(id: string, partial: Partial<Product>): Promise<Product> {\n const { core } = getClients()\n const tenantId = getTenantId()\n const row: Record<string, unknown> = {}\n if (partial.name !== undefined) row.name = partial.name\n if (partial.description !== undefined) row.description = partial.description\n if (partial.sku !== undefined) row.sku = partial.sku\n if (partial.salePrice !== undefined) row.price = partial.salePrice\n if (partial.costPrice !== undefined) row.cost = partial.costPrice\n if (partial.minQuantity !== undefined) row.min_stock = partial.minQuantity\n if (partial.isActive !== undefined) row.is_active = partial.isActive\n if (partial.imageUrl !== undefined) row.image_url = partial.imageUrl\n\n const metaPatch: Record<string, unknown> = {}\n if (partial.productType !== undefined) metaPatch.productType = partial.productType\n if (partial.barcode !== undefined) metaPatch.barcode = partial.barcode\n if (partial.brand !== undefined) metaPatch.brand = partial.brand\n if (partial.maxQuantity !== undefined) metaPatch.maxQuantity = partial.maxQuantity\n if (Object.keys(metaPatch).length > 0) {\n // Merge, never replace: this used to assign a fresh object, which wiped\n // every key the caller did not happen to mention (maxQuantity most of\n // all) and wrote undefined for the ones it mentioned but left unset.\n const { data: current } = await core.from('products').select('metadata').eq('id', id).single()\n row.metadata = { ...(current?.metadata ?? {}), ...metaPatch }\n }\n\n if (Object.keys(row).length > 0) {\n const { error } = await core.from('products').update(row).eq('id', id)\n if (error) throw new Error(error.message)\n }\n\n const details = productDetailsRow(partial)\n if (details) {\n const { error: detailsError } = await core.from(T.productDetails)\n .upsert({ ...details, product_id: id, tenant_id: tenantId }, { onConflict: 'product_id' })\n if (detailsError) throw new Error(detailsError.message)\n }\n\n const updated = await provider.getProductById(id)\n if (!updated) throw new Error(`Product ${id} not found after update`)\n return updated\n },\n\n async uploadProductImage(productId: string, file: File): Promise<string> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('Nenhum estabelecimento ativo para enviar a foto.')\n if (!file.type.startsWith('image/')) throw new Error('Selecione um arquivo de imagem.')\n if (file.size > 8 * 1024 * 1024) throw new Error('A foto deve ter no máximo 8 MB.')\n\n const extension = file.name.split('.').pop()?.toLowerCase().replace(/[^a-z0-9]/g, '') || 'jpg'\n const objectId = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`\n const path = `${tenantId}/products/${productId}/${objectId}.${extension}`\n const bucket = core.storage.from('inventory-images')\n const { error: uploadError } = await bucket.upload(path, file, {\n cacheControl: '31536000',\n contentType: file.type,\n upsert: false,\n })\n if (uploadError) throw new Error(uploadError.message)\n\n const { data: { publicUrl } } = bucket.getPublicUrl(path)\n const { error: registerError } = await core.rpc('inventory_register_product_image', {\n p_product: productId,\n p_storage_path: path,\n p_public_url: publicUrl,\n p_file_name: file.name,\n p_file_size: file.size,\n p_mime_type: file.type,\n })\n if (registerError) {\n // A file without a canonical document row becomes permanent garbage.\n // Best-effort cleanup keeps a failed register call recoverable.\n await bucket.remove([path])\n throw new Error(registerError.message)\n }\n return publicUrl\n },\n\n // --- Stock Movements (via view with product join — single query) ---\n async getMovements(query: MovementQuery): Promise<PaginatedResult<StockMovement>> {\n const { pub } = getClients()\n // Single query via v_stock_movements view (JOINs with public.products)\n let qb = pub.from('v_stock_movements').select('*', { count: 'exact' })\n if (query.productId) qb = qb.eq('product_id', query.productId)\n if (query.movementType) {\n const types = Array.isArray(query.movementType) ? query.movementType : [query.movementType]\n qb = qb.in('movement_type', types)\n }\n if (query.stockLocationId) qb = qb.eq('stock_location_id', query.stockLocationId)\n if (query.dateRange) qb = qb.gte('movement_date', query.dateRange.from).lte('movement_date', query.dateRange.to)\n if (query.search) qb = qb.ilike('product_name', `%${query.search}%`)\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 50\n qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order('movement_date', { ascending: false })\n const { data, count } = await qb\n\n const movements = (data ?? []).map((r: any) => {\n const mov = snakeToCamel(r) as any\n mov.productName = r.product_name ?? mov.productName\n mov.productSku = r.product_sku ?? mov.productSku\n // View may include location names if the updated migration has been applied\n mov.stockLocationName = r.stock_location_name ?? mov.stockLocationName\n mov.destinationLocationName = r.destination_location_name ?? mov.destinationLocationName\n return mov as StockMovement\n })\n\n // Resolve location names if not provided by the view\n const needsLocationResolve = movements.some(\n (m: any) => (m.stockLocationId && !m.stockLocationName) || (m.destinationLocationId && !m.destinationLocationName)\n )\n if (needsLocationResolve) {\n const locationIds = new Set<string>()\n for (const m of movements) {\n if (m.stockLocationId && !m.stockLocationName) locationIds.add(m.stockLocationId)\n if (m.destinationLocationId && !m.destinationLocationName) locationIds.add(m.destinationLocationId)\n }\n if (locationIds.size > 0) {\n const { data: locs } = await pub.from(T.stockLocations).select('id, name').in('id', [...locationIds])\n const locMap = new Map((locs ?? []).map((l: any) => [l.id, l.name]))\n for (const m of movements) {\n if (m.stockLocationId && !m.stockLocationName) m.stockLocationName = locMap.get(m.stockLocationId)\n if (m.destinationLocationId && !m.destinationLocationName) m.destinationLocationName = locMap.get(m.destinationLocationId)\n }\n }\n }\n\n return { data: movements, total: count ?? 0 }\n },\n\n async createMovement(input: CreateStockMovementInput): Promise<StockMovement> {\n const { core, pub } = getClients()\n const tenantId = getTenantId()\n const unitCost = input.unitCost ?? 0\n const row = {\n ...camelToSnake(input as any),\n tenant_id: tenantId,\n unit_cost: unitCost,\n total_cost: unitCost * input.quantity,\n movement_date: input.movementDate ?? new Date().toISOString().slice(0, 10),\n }\n const { data, error } = await pub.from(T.stockMovements).insert(row).select().single()\n if (error) throw new Error(error.message)\n\n // Fetch product name + current stock for the response and stock update\n const { data: product } = await core.from('products').select('id, name, stock').eq('id', input.productId).single()\n\n // How much on-hand actually moved. For entry/exit/loss it is the typed\n // quantity signed; for an adjustment it is only known once the slot has\n // been read, because an adjustment SETS the slot rather than shifting it.\n let stockDelta =\n input.movementType === 'entry' ? input.quantity\n : input.movementType === 'exit' || input.movementType === 'loss' ? -input.quantity\n : 0\n\n // Update stock_positions when a location is specified. This is NOT\n // best-effort: it used to swallow every failure behind a console.warn,\n // which meant the ledger and the on-hand balance could silently diverge —\n // the single worst thing an inventory module can do quietly.\n if (input.stockLocationId) {\n // An `adjustment` declares effect 'set' in the movement vocabulary: the\n // quantity is the counted truth. It used to be subtracted like an exit,\n // so counting 10 of something you had 10 of drove the slot to zero.\n const mode = input.movementType === 'adjustment' ? 'set' : 'add'\n const amount = mode === 'set'\n ? input.quantity\n : (input.movementType === 'entry' ? input.quantity : -input.quantity)\n const applied = await applyPositionDelta(pub, tenantId, input, input.stockLocationId, amount, mode)\n if (input.movementType === 'adjustment') stockDelta = applied\n\n // A transfer leaves the origin and arrives at the destination, so the\n // product's total is unchanged.\n if (input.movementType === 'transfer' && input.destinationLocationId) {\n await applyPositionDelta(pub, tenantId, input, input.destinationLocationId, input.quantity)\n stockDelta = 0\n }\n } else if (input.movementType === 'adjustment') {\n // No location to read a slot from — the counted quantity is the total.\n stockDelta = input.quantity - (Number(product?.stock) || 0)\n }\n\n if (product && stockDelta !== 0) {\n await core.from('products').update({ stock: (Number(product.stock) || 0) + stockDelta }).eq('id', input.productId)\n }\n\n const movement = snakeToCamel(data) as any\n movement.productName = product?.name\n // Resolve location name\n if (input.stockLocationId) {\n const { data: loc } = await pub.from(T.stockLocations).select('name').eq('id', input.stockLocationId).single()\n movement.stockLocationName = loc?.name\n }\n if (input.destinationLocationId) {\n const { data: loc } = await pub.from(T.stockLocations).select('name').eq('id', input.destinationLocationId).single()\n movement.destinationLocationName = loc?.name\n }\n if (input.supplierId) {\n const { data: supplier } = await core.from('people').select('name').eq('id', input.supplierId).single()\n movement.supplierName = supplier?.name\n }\n return movement as StockMovement\n },\n\n /**\n * Undo a movement: the ledger row goes and the stock it moved comes back.\n * Position and on-hand are unwound with the same rules createMovement\n * applied, so a reversal cannot leave the two disagreeing.\n */\n async reverseMovement(movementId: string): Promise<void> {\n const { core, pub } = getClients()\n const tenantId = getTenantId()\n const { data: row, error } = await pub.from(T.stockMovements).select('*').eq('id', movementId).single()\n if (error) throw new Error(error.message)\n if (!row) throw new Error(`Movement ${movementId} not found`)\n\n const movementType = row.movement_type as MovementType\n const quantity = Number(row.quantity) || 0\n // Same slot key the movement wrote to; unit_cost follows the undone\n // movement because no earlier cost survives on the position.\n const slot: CreateStockMovementInput = {\n productId: row.product_id,\n quantity,\n movementType,\n unitCost: row.unit_cost ?? 0,\n batchNumber: row.batch_number ?? undefined,\n expirationDate: row.expiration_date ?? undefined,\n }\n\n // The ledger row goes FIRST, and `select()` is what makes a delete the RLS\n // refused fail loudly — PostgREST reports deleting nothing as success, and\n // unwinding the stock behind that would leave the two disagreeing.\n const { data: deleted, error: deleteError } = await pub.from(T.stockMovements)\n .delete().eq('id', movementId).select('id')\n if (deleteError) throw new Error(deleteError.message)\n if (!deleted || deleted.length === 0) throw new Error(`Movement ${movementId} could not be deleted`)\n\n if (movementType !== 'adjustment' && movementType !== 'transfer') {\n const { data: product } = await core.from('products').select('stock').eq('id', row.product_id).single()\n if (product) {\n const delta = movementType === 'entry' ? -quantity : quantity\n await core.from('products').update({ stock: (product.stock ?? 0) + delta }).eq('id', row.product_id)\n }\n }\n\n if (row.stock_location_id) {\n await applyPositionDelta(pub, tenantId, slot, row.stock_location_id, movementType === 'entry' ? -quantity : quantity)\n if (movementType === 'transfer' && row.destination_location_id) {\n await applyPositionDelta(pub, tenantId, slot, row.destination_location_id, -quantity)\n }\n }\n },\n\n // --- Stock Positions ---\n async getPositions(productId: string): Promise<StockPosition[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.stockPositions).select('*').eq('product_id', productId)\n const positions: StockPosition[] = (data ?? []).map((r: any) => snakeToCamel(r) as unknown as StockPosition)\n\n const locationIds = [...new Set(positions.map((p) => p.stockLocationId).filter(Boolean) as string[])]\n if (locationIds.length > 0) {\n const { data: locs } = await pub.from(T.stockLocations).select('id, name').in('id', locationIds)\n const byId = new Map<string, string>((locs ?? []).map((l: any) => [l.id, l.name]))\n for (const p of positions) {\n if (p.stockLocationId) p.stockLocationName = byId.get(p.stockLocationId)\n }\n }\n return positions\n },\n\n // --- Stock Locations ---\n async getLocations(): Promise<StockLocation[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.stockLocations).select('*').eq('is_active', true).order('name')\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as StockLocation)\n },\n\n async createLocation(input): Promise<StockLocation> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { data } = await pub.from(T.stockLocations).insert({ ...camelToSnake(input as any), tenant_id: tenantId }).select().single()\n return snakeToCamel(data!) as unknown as StockLocation\n },\n\n // --- Suppliers (same rows the suppliers registry edits) ---\n async getSuppliers(): Promise<Supplier[]> {\n const { core } = getClients()\n const { data } = await core.from('people')\n .select('id, name, document_number, phone')\n .eq('kind', 'supplier').eq('is_active', true)\n .order('name').limit(200)\n return (data ?? []).map((r: any) => ({\n id: r.id, name: r.name,\n documentNumber: r.document_number ?? undefined,\n phone: r.phone ?? undefined,\n }))\n },\n\n // --- Categories ---\n async getCategories(): Promise<ProductCategory[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.productCategories).select('*').eq('is_active', true).order('name')\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as ProductCategory)\n },\n\n // --- Stock counts ---\n async getCountSessions(): Promise<StockCountSession[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countSessions)\n .select(COUNT_SESSION_SELECT).order('opened_at', { ascending: false }).limit(100)\n const sessions: StockCountSession[] = (data ?? []).map(mapCountSessionRow)\n if (sessions.length === 0) return sessions\n\n // The progress columns in one round trip instead of a query per row.\n const { data: lines } = await pub.from(T.countItems)\n .select('session_id, system_quantity, counted_quantity')\n .in('session_id', sessions.map((s) => s.id))\n const tally = new Map<string, { total: number; counted: number; divergent: number }>()\n for (const line of lines ?? []) {\n const bucket = tally.get(line.session_id) ?? { total: 0, counted: 0, divergent: 0 }\n bucket.total += 1\n if (line.counted_quantity != null) {\n bucket.counted += 1\n if (Number(line.counted_quantity) !== Number(line.system_quantity)) bucket.divergent += 1\n }\n tally.set(line.session_id, bucket)\n }\n for (const session of sessions) {\n const bucket = tally.get(session.id)\n session.itemCount = bucket?.total ?? 0\n session.countedCount = bucket?.counted ?? 0\n session.divergentCount = bucket?.divergent ?? 0\n }\n return sessions\n },\n\n async getCountSession(id: string): Promise<StockCountSession | null> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countSessions).select(COUNT_SESSION_SELECT).eq('id', id).maybeSingle()\n return data ? mapCountSessionRow(data) : null\n },\n\n async getCountItems(sessionId: string): Promise<StockCountItem[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countItems)\n .select('*, products(name, sku)').eq('session_id', sessionId)\n const items: StockCountItem[] = (data ?? []).map(mapCountItemRow)\n return items.sort((a, b) => (a.productName ?? '').localeCompare(b.productName ?? ''))\n },\n\n async openCountSession(input: OpenStockCountInput): Promise<StockCountSession> {\n const { pub } = getClients()\n // The snapshot has to be one consistent read, so the RPC does both.\n const { data, error } = await pub.rpc('inventory_open_count_session', {\n p_stock_location_id: input.stockLocationId,\n p_category_id: input.categoryId ?? null,\n p_reference: input.reference ?? null,\n p_blind: input.blind ?? true,\n p_notes: input.notes ?? null,\n })\n if (error) throw new Error(error.message)\n const session = await provider.getCountSession(data as string)\n if (!session) throw new Error('Count session could not be read after opening')\n return session\n },\n\n async saveCountEntry(itemId: string, quantity: number | null, notes?: string): Promise<StockCountItem> {\n const { pub } = getClients()\n const row: Record<string, unknown> = {\n counted_quantity: quantity,\n counted_at: quantity == null ? null : new Date().toISOString(),\n updated_at: new Date().toISOString(),\n }\n if (notes !== undefined) row.notes = notes || null\n const { data, error } = await pub.from(T.countItems)\n .update(row).eq('id', itemId).select('*, products(name, sku)').single()\n if (error) throw new Error(error.message)\n\n // The first entry typed is what turns an open session into a count.\n await pub.from(T.countSessions)\n .update({ status: 'counting', updated_at: new Date().toISOString() })\n .eq('id', data.session_id).eq('status', 'open')\n return mapCountItemRow(data)\n },\n\n async closeCountSession(sessionId: string, reason?: string): Promise<CloseStockCountResult> {\n const { pub } = getClients()\n const { data, error } = await pub.rpc('inventory_close_count_session', {\n p_session_id: sessionId,\n p_reason: reason ?? null,\n })\n if (error) throw new Error(error.message)\n const result = (data ?? {}) as Record<string, any>\n if (result.ok === false) throw new Error(result.error ?? 'Could not close the count')\n return {\n sessionId,\n adjustmentsCreated: Number(result.adjustments_created) || 0,\n alreadyClosed: result.already_closed === true,\n }\n },\n\n async cancelCountSession(sessionId: string): Promise<StockCountSession> {\n const { pub } = getClients()\n // `.neq('status','closed')` is the fence: a closed count has already moved\n // stock and cancelling it would claim otherwise.\n const { error } = await pub.from(T.countSessions)\n .update({ status: 'cancelled', updated_at: new Date().toISOString() })\n .eq('id', sessionId).neq('status', 'closed')\n if (error) throw new Error(error.message)\n const session = await provider.getCountSession(sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n return session\n },\n\n // --- Recipes ---\n async getRecipes(): Promise<Recipe[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipes).select('*').eq('is_active', true).order('name')\n supabaseError('Could not read recipes', error)\n return hydrateRecipeRows(pub, data ?? [])\n },\n\n async getRecipeById(id: string): Promise<Recipe | null> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipes).select('*').eq('id', id).maybeSingle()\n supabaseError('Could not read recipe', error)\n if (!data) return null\n return (await hydrateRecipeRows(pub, [data]))[0] ?? null\n },\n\n async getRecipeIngredients(recipeId: string): Promise<RecipeIngredient[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeIngredients)\n .select('*')\n .eq('recipe_id', recipeId)\n .order('display_order')\n supabaseError('Could not read recipe ingredients', error)\n return hydrateRecipeIngredientRows(pub, data ?? [], true)\n },\n\n async getAllRecipeIngredients(): Promise<RecipeIngredient[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeIngredients)\n .select('*')\n .order('display_order')\n supabaseError('Could not read recipe ingredients', error)\n return hydrateRecipeIngredientRows(pub, data ?? [], false)\n },\n\n async getRecipeGroups(recipeId: string): Promise<RecipeGroup[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeGroups).select('*').eq('recipe_id', recipeId).order('display_order')\n supabaseError('Could not read recipe groups', error)\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as RecipeGroup)\n },\n\n async createRecipe(input: CreateRecipeInput): Promise<Recipe> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { ingredients, ...recipeData } = input\n const { data: recipe, error: recipeError } = await pub.from(T.recipes)\n .insert({ ...camelToSnake(recipeData as any), tenant_id: tenantId })\n .select().single()\n supabaseError('Could not create recipe', recipeError)\n if (!recipe) throw new Error('Could not create recipe: Supabase returned no row')\n\n if (ingredients.length > 0) {\n const { error: ingredientsError } = await pub.from(T.recipeIngredients).insert(\n ingredients.map((ing) => ({ ...camelToSnake(ing as any), recipe_id: recipe.id, tenant_id: tenantId }))\n )\n if (ingredientsError) {\n // Do not leave a recipe that says it was saved while carrying no\n // technical sheet. This best-effort compensation keeps the direct\n // browser flow coherent until it moves to an atomic RPC.\n await pub.from(T.recipes).delete().eq('id', recipe.id)\n supabaseError('Could not create recipe ingredients', ingredientsError)\n }\n }\n\n // One active ficha per product. The form only ever creates, so re-saving\n // left the previous recipe active too — and `consumeRecipeForSource` reads\n // a SINGLE active recipe per product, which means a stale duplicate could\n // be the one deciding a stock movement. Retired only after the ingredients\n // landed, so a failed save never disables the sheet that still works.\n if (recipeData.productId) {\n const { error: retireError } = await pub.from(T.recipes)\n .update({ is_active: false })\n .eq('product_id', recipeData.productId)\n .eq('is_active', true)\n .neq('id', recipe.id)\n // The new sheet is saved and is the newest by `updated_at`, so it already\n // wins the lookup; a failed retirement is worth a warning, not a rollback.\n if (retireError) console.warn('Could not retire previous recipes', retireError.message)\n }\n\n return snakeToCamel(recipe!) as unknown as Recipe\n },\n\n async updateRecipe(id: string, patch: Partial<Recipe>): Promise<Recipe> {\n const { pub } = getClients()\n const row: Record<string, unknown> = {}\n if (patch.name !== undefined) row.name = patch.name\n if (patch.description !== undefined) row.description = patch.description\n if (patch.productId !== undefined) row.product_id = patch.productId || null\n if (patch.yieldQuantity !== undefined) row.yield_quantity = patch.yieldQuantity\n if (patch.preparationTimeMinutes !== undefined) row.preparation_time_minutes = patch.preparationTimeMinutes\n if (patch.instructions !== undefined) row.instructions = patch.instructions\n if (patch.isActive !== undefined) row.is_active = patch.isActive\n if (patch.metadata !== undefined) row.metadata = patch.metadata\n if (Object.keys(row).length > 0) {\n row.updated_at = new Date().toISOString()\n const { error } = await pub.from(T.recipes).update(row).eq('id', id)\n if (error) throw new Error(error.message)\n }\n const updated = await provider.getRecipeById(id)\n if (!updated) throw new Error(`Recipe ${id} not found after update`)\n return updated\n },\n\n async addRecipeIngredient(recipeId: string, input: CreateRecipeIngredientInput): Promise<RecipeIngredient> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { data, error } = await pub.from(T.recipeIngredients)\n .insert({ ...camelToSnake(input as any), recipe_id: recipeId, tenant_id: tenantId })\n .select('*').single()\n supabaseError('Could not add recipe ingredient', error)\n if (!data) throw new Error('Could not add recipe ingredient: Supabase returned no row')\n return (await hydrateRecipeIngredientRows(pub, [data], true))[0]\n },\n\n // --- Summary ---\n async getSummary(): Promise<InventorySummary> {\n const { core, pub } = getClients()\n const { data: products } = await core.from('products').select('stock, min_stock, price, is_active').eq('is_active', true)\n const items = products ?? []\n const lowStock = items.filter((p: any) => p.stock > 0 && p.stock <= (p.min_stock ?? 0))\n const outOfStock = items.filter((p: any) => p.stock <= 0)\n const totalValue = items.reduce((sum: number, p: any) => sum + (p.stock ?? 0) * (p.price ?? 0), 0)\n\n const weekAgo = new Date()\n weekAgo.setDate(weekAgo.getDate() - 7)\n const { data: movements } = await pub.from(T.stockMovements).select('movement_type').gte('movement_date', weekAgo.toISOString().slice(0, 10))\n const movs = movements ?? []\n const movementsByType: Record<MovementType, number> = { entry: 0, exit: 0, adjustment: 0, transfer: 0, loss: 0 }\n for (const m of movs) movementsByType[m.movement_type as MovementType]++\n\n return {\n totalProducts: items.length,\n lowStockCount: lowStock.length,\n outOfStockCount: outOfStock.length,\n totalStockValue: totalValue,\n recentMovementCount: movs.length,\n movementsByType,\n }\n },\n }\n\n return provider\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { dedup } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport type { InventoryDataProvider } from './data/types'\nimport type {\n Product, StockMovement, StockLocation, Recipe,\n InventorySummary, ProductQuery, MovementQuery,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput,\n} from './types'\n\nexport interface InventoryUIState {\n products: Product[]\n productsTotal: number\n productsLoading: boolean\n productQuery: ProductQuery\n\n movements: StockMovement[]\n movementsTotal: number\n movementsLoading: boolean\n\n locations: StockLocation[]\n locationsLoading: boolean\n\n recipes: Recipe[]\n recipesLoading: boolean\n\n summary: InventorySummary | null\n summaryLoading: boolean\n\n fetchSummary(): Promise<void>\n fetchProducts(query: ProductQuery): Promise<void>\n fetchMovements(query: MovementQuery): Promise<void>\n fetchLocations(): Promise<void>\n fetchRecipes(): Promise<void>\n createProduct(input: CreateProductInput): Promise<Product>\n createMovement(input: CreateStockMovementInput): Promise<StockMovement>\n createRecipe(input: CreateRecipeInput): Promise<Recipe>\n}\n\nexport function createInventoryStore(provider: InventoryDataProvider): StoreApi<InventoryUIState> {\n return createStore<InventoryUIState>((set, get) => ({\n products: [], productsTotal: 0, productsLoading: false, productQuery: {},\n movements: [], movementsTotal: 0, movementsLoading: false,\n locations: [], locationsLoading: false,\n recipes: [], recipesLoading: false,\n summary: null, summaryLoading: false,\n\n async fetchSummary() {\n return dedup('inv:summary', async () => {\n set({ summaryLoading: true })\n const summary = await provider.getSummary()\n set({ summary, summaryLoading: false })\n })\n },\n\n async fetchProducts(query) {\n const key = 'inv:products:' + JSON.stringify(query)\n return dedup(key, async () => {\n set({ productsLoading: true, productQuery: query })\n const result = await provider.getProducts(query)\n set({ products: result.data, productsTotal: result.total, productsLoading: false })\n })\n },\n\n async fetchMovements(query) {\n return dedup('inv:movements:' + JSON.stringify(query), async () => {\n set({ movementsLoading: true })\n const result = await provider.getMovements(query)\n set({ movements: result.data, movementsTotal: result.total, movementsLoading: false })\n })\n },\n\n async fetchLocations() {\n return dedup('inv:locations', async () => {\n set({ locationsLoading: true })\n const locations = await provider.getLocations()\n set({ locations, locationsLoading: false })\n })\n },\n\n async fetchRecipes() {\n set({ recipesLoading: true })\n const recipes = await provider.getRecipes()\n set({ recipes, recipesLoading: false })\n },\n\n async createProduct(input) {\n try {\n const product = await provider.createProduct(input)\n const query = get().productQuery\n const [result, summary] = await Promise.all([provider.getProducts(query), provider.getSummary()])\n set({ products: result.data, productsTotal: result.total, summary })\n toast.success('Product created')\n return product\n } catch (err: any) {\n toast.error('Failed to create product', { description: err?.message })\n throw err\n }\n },\n\n async createMovement(input) {\n try {\n const movement = await provider.createMovement(input)\n const [summary] = await Promise.all([provider.getSummary()])\n set({ summary })\n toast.success('Stock movement recorded')\n return movement\n } catch (err: any) {\n toast.error('Failed to record movement', { description: err?.message })\n throw err\n }\n },\n\n async createRecipe(input) {\n try {\n const recipe = await provider.createRecipe(input)\n const recipes = await provider.getRecipes()\n set({ recipes })\n toast.success('Recipe created')\n return recipe\n } catch (err: any) {\n toast.error('Failed to create recipe', { description: err?.message })\n throw err\n }\n },\n }))\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { T } from './tables'\n\nconst supplierEntity: EntityDef = {\n name: 'Supplier',\n namePlural: 'Suppliers',\n icon: 'Building2',\n layout: 'person',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, searchable: true },\n { key: 'phone', label: 'Phone', type: 'phone', showInTable: true },\n { key: 'email', label: 'Email', type: 'email', showInTable: true },\n { key: 'documentNumber', label: 'Tax ID', type: 'text', showInTable: true },\n // No address field: a supplier has as many as the operation needs (the\n // office that invoices, the warehouse the goods leave from). `layout:\n // 'person'` gives the record an \"Addresses\" tab backed by public.addresses,\n // which is the same relation clients and patients already use.\n { key: 'notes', label: 'Notes', type: 'textarea' },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: {\n table: 'people',\n tenantScoped: true,\n filters: { kind: 'supplier' },\n defaults: { kind: 'supplier' },\n },\n}\n\nconst measurementUnitEntity: EntityDef = {\n name: 'Measurement Unit',\n namePlural: 'Measurement Units',\n icon: 'Ruler',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'abbreviation', label: 'Abbreviation', type: 'text', required: true, showInTable: true },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.measurementUnits, tenantScoped: true },\n}\n\nconst productCategoryEntity: EntityDef = {\n name: 'Product Category',\n namePlural: 'Product Categories',\n icon: 'Tag',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'parentId', label: 'Parent', type: 'text', showInTable: false },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.productCategories, tenantScoped: true },\n}\n\nconst stockLocationEntity: EntityDef = {\n name: 'Stock Location',\n namePlural: 'Stock Locations',\n icon: 'Warehouse',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'description', label: 'Description', type: 'textarea', showInTable: true },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.stockLocations, tenantScoped: true },\n}\n\nexport const inventoryRegistries: PluginRegistryDef[] = [\n // --- Editable ---\n {\n id: 'suppliers',\n entity: supplierEntity,\n icon: 'Building2',\n description: 'Manage your product and material suppliers',\n display: 'table',\n },\n {\n id: 'product-categories',\n entity: productCategoryEntity,\n icon: 'Tag',\n description: 'Product categories for organization',\n display: 'table',\n },\n {\n id: 'stock-locations',\n entity: stockLocationEntity,\n icon: 'Warehouse',\n description: 'Physical storage locations for inventory',\n display: 'table',\n },\n // --- Seeded defaults, still editable by the tenant ---\n {\n id: 'measurement-units',\n entity: measurementUnitEntity,\n icon: 'Ruler',\n description: 'Standard units of measure',\n display: 'table',\n seedData: [\n { id: 'mu-unit', name: 'Unit', abbreviation: 'un', isActive: true },\n { id: 'mu-box', name: 'Box', abbreviation: 'box', isActive: true },\n { id: 'mu-kg', name: 'Kilogram', abbreviation: 'kg', isActive: true },\n { id: 'mu-g', name: 'Gram', abbreviation: 'g', isActive: true },\n { id: 'mu-l', name: 'Liter', abbreviation: 'L', isActive: true },\n { id: 'mu-ml', name: 'Milliliter', abbreviation: 'mL', isActive: true },\n ],\n },\n]\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const en: Record<string, string> = {\n \"inventory.dashboard.activeItems\": \"Active items\",\n \"inventory.dashboard.belowMinimum\": \"Below minimum\",\n \"inventory.dashboard.entries\": \"Entries:\",\n \"inventory.dashboard.exits\": \"Exits:\",\n \"inventory.dashboard.last7Days\": \"Last 7 days\",\n \"inventory.dashboard.lowStock\": \"Low Stock\",\n \"inventory.dashboard.needRestocking\": \"Need restocking\",\n \"inventory.dashboard.outOfStock\": \"Out of Stock\",\n \"inventory.dashboard.quickActions\": \"Quick Actions\",\n \"inventory.dashboard.quickActionsDesc\": \"Use the sidebar to record stock entries, exits, or manage products.\",\n \"inventory.dashboard.recentActivity\": \"Recent Activity\",\n \"inventory.dashboard.stockValue\": \"Stock Value\",\n \"inventory.dashboard.totalProducts\": \"Total Products\",\n \"inventory.dashboard.totalValue\": \"Total inventory value\",\n \"inventory.history.noMovements\": \"No movements recorded\",\n \"inventory.history.columnDate\": \"Date\",\n \"inventory.history.columnProduct\": \"Product\",\n \"inventory.history.columnType\": \"Type\",\n \"inventory.history.columnLocation\": \"Location\",\n \"inventory.history.columnQty\": \"Qty\",\n \"inventory.history.columnTotal\": \"Total\",\n \"inventory.history.newEntry\": \"New entry\",\n \"inventory.history.newExit\": \"Exit\",\n \"inventory.nav.recipes\": \"Recipes\",\n \"registry.suppliers\": \"Suppliers\",\n \"registry.suppliers.description\": \"Who you buy from\",\n \"registry.product-categories\": \"Categories\",\n \"registry.product-categories.description\": \"How the catalogue is grouped\",\n \"registry.stock-locations\": \"Stock locations\",\n \"registry.stock-locations.description\": \"Where stock physically sits — cold room, dry store, freezer\",\n \"registry.measurement-units\": \"Units of measure\",\n \"registry.measurement-units.description\": \"How each item is counted\",\n \"inventory.history.searchPlaceholder\": \"Search movements...\",\n \"inventory.history.subtitle\": \"All stock movements\",\n \"inventory.history.title\": \"Stock History\",\n \"inventory.nav.dashboard\": \"Dashboard\",\n \"inventory.nav.entry\": \"Entry\",\n \"inventory.nav.exit\": \"Exit\",\n \"inventory.nav.history\": \"History\",\n \"inventory.nav.list\": \"List\",\n \"inventory.nav.new\": \"New\",\n \"inventory.nav.products\": \"Products\",\n \"inventory.nav.stock\": \"Stock\",\n \"inventory.page.newProduct\": \"New Product\",\n \"inventory.page.newProductDesc\": \"Add a product to your catalog\",\n \"inventory.page.settingsSubtitle\": \"Preferences, suppliers, categories, and units\",\n \"inventory.page.settingsTitle\": \"Inventory Settings\",\n \"inventory.page.stockEntry\": \"Stock Entry\",\n \"inventory.page.stockEntryDesc\": \"Record goods received\",\n \"inventory.page.stockExit\": \"Stock Exit\",\n \"inventory.page.stockExitDesc\": \"Record goods used or sold\",\n \"inventory.recipeDetail.active\": \"Active\",\n \"inventory.recipeDetail.backToList\": \"Back to list\",\n \"inventory.recipeDetail.inactive\": \"Inactive\",\n \"inventory.recipeDetail.ingredientCount\": \"Ingredients\",\n \"inventory.recipeDetail.ingredientsTitle\": \"Ingredients\",\n \"inventory.recipeDetail.instructions\": \"Instructions\",\n \"inventory.recipeDetail.noIngredients\": \"No ingredients defined\",\n \"inventory.recipeDetail.notFound\": \"Recipe not found\",\n \"inventory.recipeDetail.prepTime\": \"Prep time\",\n \"inventory.recipeDetail.produces\": \"Produces\",\n \"inventory.recipeDetail.recipes\": \"Recipes\",\n \"inventory.recipeDetail.yield\": \"Yield\",\n \"inventory.recipes.createFirst\": \"Create your first recipe\",\n \"inventory.recipes.ingredients\": \"Ingredients\",\n \"inventory.recipes.newRecipe\": \"New Recipe\",\n \"inventory.recipes.noRecipes\": \"No recipes yet\",\n \"inventory.recipes.produces\": \"Produces:\",\n \"inventory.recipes.productionFormulas\": \"{{count}} production formulas\",\n \"inventory.recipes.recipesDesc\": \"Recipes define how to produce products from ingredients\",\n \"inventory.recipes.title\": \"Recipes\",\n \"inventory.recipes.yield\": \"Yield\",\n \"inventory.stock.additionalDetails\": \"Additional details (optional)\",\n \"inventory.stock.adjustmentDesc\": \"Count correction\",\n \"inventory.stock.adjustmentLabel\": \"Adjustment\",\n \"inventory.stock.back\": \"Back\",\n \"inventory.stock.batchNumber\": \"Batch Number\",\n \"inventory.stock.currentStock\": \"Current Stock\",\n \"inventory.stock.destination\": \"Destination\",\n \"inventory.stock.document\": \"Document\",\n \"inventory.stock.documentNumber\": \"Document Number\",\n \"inventory.stock.entry\": \"Stock Entry\",\n \"inventory.stock.entryDesc\": \"Receiving goods\",\n \"inventory.stock.entryLabel\": \"Entry\",\n \"inventory.stock.exit\": \"Stock Exit\",\n \"inventory.stock.exitDesc\": \"Using or selling\",\n \"inventory.stock.exitLabel\": \"Exit\",\n \"inventory.stock.expirationDate\": \"Expiration Date\",\n \"inventory.stock.fromLocation\": \"From Location\",\n \"inventory.stock.locationLabel\": \"Location\",\n \"inventory.stock.lossDesc\": \"Waste or damage\",\n \"inventory.stock.lossLabel\": \"Loss\",\n \"inventory.stock.movement\": \"Stock Movement\",\n \"inventory.stock.movementDetails\": \"Movement Details\",\n \"inventory.stock.movementType\": \"Movement type\",\n \"inventory.stock.next\": \"Next\",\n \"inventory.stock.notes\": \"Notes\",\n \"inventory.stock.product\": \"Product\",\n \"inventory.stock.quantity\": \"Quantity *\",\n \"inventory.stock.quantityLabel\": \"Quantity\",\n \"inventory.stock.reason\": \"Reason *\",\n \"inventory.stock.reasonLabel\": \"Reason\",\n \"inventory.stock.recordMovement\": \"Record Movement\",\n \"inventory.stock.recorded\": \"Recorded\",\n \"inventory.stock.recording\": \"Recording...\",\n \"inventory.stock.searchProduct\": \"Search by name, SKU, or barcode...\",\n \"inventory.stock.stepOf\": \"Step {{step}} of 3\",\n \"inventory.stock.supplier\": \"Supplier\",\n \"inventory.stock.toLocation\": \"To Location *\",\n \"inventory.stock.total\": \"Total\",\n \"inventory.stock.totalCost\": \"Total Cost\",\n \"inventory.stock.transferDesc\": \"Between locations\",\n \"inventory.stock.transferLabel\": \"Transfer\",\n \"inventory.stock.unitCost\": \"Unit Cost\",\n \"inventory.stock.unitCostLabel\": \"Unit Cost\",\n \"inventory.stock.searchSupplier\": \"Search supplier...\",\n \"inventory.stock.noSuppliers\": \"No supplier registered\",\n \"inventory.productDetail.stockTab\": \"Stock\",\n \"inventory.productDetail.positionsTitle\": \"Stock by location\",\n \"inventory.productDetail.onHand\": \"On hand\",\n \"inventory.productDetail.noPositions\": \"No stock in any location\",\n \"inventory.productDetail.historyTitle\": \"Movement history\",\n \"inventory.productDetail.undoLast\": \"Undo last movement\",\n \"inventory.productDetail.undoTitle\": \"Undo the last movement?\",\n \"inventory.productDetail.undoDescription\": \"{{type}} of {{quantity}} on {{date}} leaves the history, and the stock it moved goes back.\",\n \"inventory.productDetail.undoConfirm\": \"Undo\",\n \"inventory.productDetail.undone\": \"Movement undone\",\n \"inventory.productDetail.undoFailed\": \"Could not undo the movement\",\n \"inventory.productDetail.notFound\": \"Product not found\",\n \"inventory.productDetail.backToList\": \"Back to products\",\n \"inventory.onboarding.welcome\": \"Welcome to Inventory\",\n \"inventory.onboarding.description\": \"Track products, manage stock levels, and monitor movements across your business.\",\n \"inventory.onboarding.skip\": \"Skip setup\",\n \"inventory.onboarding.getStarted\": \"Get Started\",\n \"inventory.onboarding.units.title\": \"Measurement Units\",\n \"inventory.onboarding.units.description\": \"Default units (Unit, Box, Kg, L, etc.) are ready. Customize them anytime in Settings.\",\n \"inventory.onboarding.locations.title\": \"Stock Locations\",\n \"inventory.onboarding.locations.description\": \"A default storage location has been created. Add more for multi-location tracking.\",\n \"inventory.onboarding.start\": \"Start using Inventory\",\n \"inventory.onboarding.preparing\": \"Preparing inventory...\",\n \"inventory.onboarding.setupError\": \"We could not prepare the default units and stock location. Try again.\",\n \"inventory.quickActions.newProduct\": \"New Product\",\n \"inventory.quickActions.newProductDesc\": \"Add a product to your catalog\",\n \"inventory.quickActions.stockEntry\": \"Stock Entry\",\n \"inventory.quickActions.stockEntryDesc\": \"Record goods received\",\n \"inventory.quickActions.stockExit\": \"Stock Exit\",\n \"inventory.quickActions.stockExitDesc\": \"Record goods used or sold\",\n \"inventory.settingsPage.title\": \"Inventory Settings\",\n \"inventory.settingsPage.subtitle\": \"Manage units, categories, and stock locations\",\n \"inventory.settings.stockManagement\": \"Stock Management\",\n \"inventory.settings.stockManagementDesc\": \"How stock levels are tracked\",\n \"inventory.settings.lowStockAlerts\": \"Low stock alerts\",\n \"inventory.settings.lowStockAlertsDesc\": \"Show warnings when products fall below minimum quantity\",\n \"inventory.settings.requireReason\": \"Require reason for adjustments\",\n \"inventory.settings.requireReasonDesc\": \"Make reason mandatory for stock adjustments and losses\",\n \"inventory.settings.autoDeduct\": \"Auto-deduct on service\",\n \"inventory.settings.autoDeductDesc\": \"Automatically deduct products when a service is executed\",\n \"inventory.settings.products\": \"Products\",\n \"inventory.settings.productsDesc\": \"Product catalog behavior\",\n \"inventory.settings.requireSku\": \"Require SKU\",\n \"inventory.settings.requireSkuDesc\": \"Make SKU mandatory when creating products\",\n \"inventory.settings.allowNegative\": \"Allow negative stock\",\n \"inventory.settings.allowNegativeDesc\": \"Allow stock quantities to go below zero\",\n \"inventory.settings.notifications\": \"Notifications\",\n \"inventory.settings.notificationsDesc\": \"Alerts and reminders\",\n \"inventory.settings.lowStockEmail\": \"Low stock email alerts\",\n \"inventory.settings.lowStockEmailDesc\": \"Send email when products reach minimum quantity\",\n \"inventory.settings.expiryWarnings\": \"Expiry date warnings\",\n \"inventory.settings.expiryWarningsDesc\": \"Alert before products expire (batch tracking)\",\n \"inventory.productForm.newProduct\": \"New Product\",\n \"inventory.productForm.editProduct\": \"Edit Product\",\n \"inventory.productForm.updateDetails\": \"Update product details\",\n \"inventory.productForm.addToCatalog\": \"Add a product to your catalog\",\n \"inventory.productForm.cancel\": \"Cancel\",\n \"inventory.productForm.save\": \"Save\",\n \"inventory.productForm.saving\": \"Saving...\",\n \"inventory.productForm.generalInfo\": \"General Information\",\n \"inventory.productForm.name\": \"Name\",\n \"inventory.productForm.namePlaceholder\": \"Product name\",\n \"inventory.productForm.brand\": \"Brand\",\n \"inventory.productForm.brandPlaceholder\": \"Brand name\",\n \"inventory.productForm.sku\": \"SKU\",\n \"inventory.productForm.skuPlaceholder\": \"Internal code\",\n \"inventory.productForm.barcode\": \"Barcode\",\n \"inventory.productForm.barcodePlaceholder\": \"EAN / UPC\",\n \"inventory.productForm.description\": \"Description\",\n \"inventory.productForm.descriptionPlaceholder\": \"Additional information about the product\",\n \"inventory.productForm.classification\": \"Classification\",\n \"inventory.productForm.classificationDesc\": \"How this product is used in your business\",\n \"inventory.productForm.typeIngredient\": \"Raw material used in production or services\",\n \"inventory.productForm.typeSale\": \"Sold directly to customers\",\n \"inventory.productForm.typeIntermediate\": \"Produced internally from other items\",\n \"inventory.productForm.typeAsset\": \"Fixed asset for patrimony tracking\",\n \"inventory.productForm.pricing\": \"Pricing\",\n \"inventory.productForm.costPrice\": \"Cost Price\",\n \"inventory.productForm.salePrice\": \"Sale Price\",\n \"inventory.productForm.margin\": \"Margin\",\n \"inventory.productForm.stockLevels\": \"Stock Levels\",\n \"inventory.productForm.stockLevelsDesc\": \"Minimum and maximum thresholds for alerts\",\n \"inventory.productForm.minQuantity\": \"Minimum Quantity\",\n \"inventory.productForm.minQuantityHint\": \"Alert when stock falls below this\",\n \"inventory.productForm.maxQuantity\": \"Maximum Quantity\",\n \"inventory.productForm.maxQuantityHint\": \"Max capacity for this product\",\n \"inventory.productForm.optional\": \"Optional\",\n \"inventory.productForm.organization\": \"Organisation\",\n \"inventory.productForm.organizationDesc\": \"Category, unit, supplier and default storage location\",\n \"inventory.productForm.category\": \"Category\",\n \"inventory.productForm.measurementUnit\": \"Unit of measure\",\n \"inventory.productForm.measurementUnitHint\": \"How this item is counted in stock\",\n \"inventory.productForm.supplier\": \"Default supplier\",\n \"inventory.productForm.defaultLocation\": \"Default location\",\n \"inventory.movementType.entry\": \"Entry\",\n \"inventory.movementType.exit\": \"Exit\",\n \"inventory.movementType.adjustment\": \"Adjustment\",\n \"inventory.movementType.transfer\": \"Transfer\",\n \"inventory.movementType.loss\": \"Loss\",\n \"inventory.recipeForm.group\": \"Stage\",\n \"inventory.recipeForm.ungrouped\": \"No stage\",\n \"inventory.productList.bulkActivate\": \"Activate\",\n \"inventory.productList.bulkActivated\": \"{{count}} product(s) activated\",\n \"inventory.productList.bulkDeactivate\": \"Deactivate\",\n \"inventory.productList.bulkDeactivated\": \"{{count}} product(s) deactivated\",\n \"inventory.productList.bulkFailed\": \"{{count}} product(s) could not be updated\",\n \"inventory.productList.bulkNothingToDo\": \"The selected products are already in that state.\",\n \"inventory.productList.filterActive\": \"Active\",\n \"inventory.productList.filterAllStatuses\": \"Active and inactive\",\n \"inventory.productList.filterInactive\": \"Inactive\",\n \"inventory.productList.filterStatus\": \"Status\",\n \"inventory.productList.inactive\": \"Inactive\",\n \"inventory.productList.title\": \"Products\",\n \"inventory.productList.subtitle\": \"{{count}} products\",\n \"inventory.productList.product\": \"Product\",\n \"inventory.productList.type\": \"Type\",\n \"inventory.productList.stock\": \"Stock\",\n \"inventory.productList.cost\": \"Cost\",\n \"inventory.productList.value\": \"Value\",\n \"inventory.productList.searchPlaceholder\": \"Search products...\",\n 'inventory.productList.aiHint': 'Describe the product and I create it.',\n 'inventory.productList.askPlaceholder': 'Describe the product…',\n 'inventory.productList.askPersona': 'Product intake',\n 'inventory.productList.askPitch': 'Tell me the product you want to add.',\n 'inventory.productList.askDescription': 'Name, price, cost, SKU, kind — tell me what you know, however you say it, and I fill in the rest sensibly. You check before it saves.',\n 'inventory.productList.askSuggestion.0': 'Black tee S/M/L, $79, cost $28',\n 'inventory.productList.askSuggestion.1': 'Add 5 sample products so I can test the store',\n 'inventory.productList.askSuggestion.2': 'A bundle of the two best sellers',\n \"inventory.productList.newProduct\": \"New Product\",\n \"inventory.productList.empty\": \"No products yet\",\n \"inventory.productList.createFirst\": \"Create your first product\",\n \"inventory.stock.unknownProduct\": \"Unknown Product\",\n \"inventory.stock.reasonLossPlaceholder\": \"e.g. Expired, damaged\",\n \"inventory.stock.reasonAdjustPlaceholder\": \"e.g. Physical count correction\",\n \"inventory.stock.documentPlaceholder\": \"Invoice, receipt, PO...\",\n \"inventory.stock.batchPlaceholder\": \"e.g. LOT001\",\n \"inventory.stock.notesPlaceholder\": \"Additional notes...\",\n \"inventory.recipeDetail.loading\": \"Loading...\",\n \"inventory.recipeDetail.ingredient\": \"Ingredient\",\n \"inventory.recipeDetail.quantity\": \"Quantity\",\n \"inventory.recipeDetail.unit\": \"Unit\",\n \"inventory.recipeDetail.notes\": \"Notes\",\n \"inventory.recipeDetail.created\": \"Created\",\n \"inventory.recipeDetail.updated\": \"Updated\",\n \"inventory.recipeForm.newRecipe\": \"New Recipe\",\n \"inventory.recipeForm.subtitle\": \"Define a production formula\",\n \"inventory.recipeForm.cancel\": \"Cancel\",\n \"inventory.recipeForm.saveRecipe\": \"Save Recipe\",\n \"inventory.recipeForm.saving\": \"Saving...\",\n \"inventory.recipeForm.recipeDetails\": \"Recipe Details\",\n \"inventory.recipeForm.recipeName\": \"Recipe Name\",\n \"inventory.recipeForm.recipeNamePlaceholder\": \"e.g. Tomato Sauce\",\n \"inventory.recipeForm.description\": \"Description\",\n \"inventory.recipeForm.descriptionPlaceholder\": \"Brief description...\",\n \"inventory.recipeForm.produces\": \"Produces (Product)\",\n \"inventory.recipeForm.searchProduct\": \"Search product...\",\n \"inventory.recipeForm.createProduct\": \"Create product\",\n \"inventory.recipeForm.yieldQuantity\": \"Yield Quantity\",\n \"inventory.recipeForm.prepTime\": \"Prep Time (min)\",\n \"inventory.recipeForm.instructions\": \"Instructions\",\n \"inventory.recipeForm.instructionsPlaceholder\": \"Step-by-step preparation instructions...\",\n \"inventory.recipeForm.ingredients\": \"Ingredients\",\n \"inventory.recipeForm.addIngredient\": \"Add Ingredient\",\n \"inventory.recipeForm.noIngredients\": \"No ingredients added\",\n \"inventory.recipeForm.addFirstIngredient\": \"Add your first ingredient\",\n \"inventory.recipeForm.ingredient\": \"Ingredient\",\n \"inventory.recipeForm.quantity\": \"Quantity\",\n \"inventory.recipeForm.notes\": \"Notes\",\n \"inventory.recipeForm.searchIngredient\": \"Search ingredient...\",\n \"inventory.recipeForm.createIngredient\": \"Create ingredient\",\n \"inventory.recipeForm.notesPlaceholder\": \"e.g. diced, fresh\",\n \"inventory.recipeForm.ingredientsConfigured\": \"{{configured}} of {{total}} ingredients configured\",\n \"inventory.title\": \"Inventory\",\n \"inventory.stock.title\": \"Stock\",\n \"inventory.stock.minStock\": \"Min. Stock\",\n \"inventory.stock.adjust\": \"Adjust Stock\",\n \"inventory.stock.lowStock\": \"Low Stock\",\n \"inventory.products.title\": \"Products\",\n \"inventory.products.create\": \"New Product\",\n \"inventory.recipes.create\": \"New Recipe\",\n \"inventory.recipes.addIngredient\": \"Add Ingredient\",\n \"inventory.recipes.cost\": \"Cost\",\n \"inventory.recipes.loading\": \"Loading...\",\n \"inventory.suppliers.title\": \"Suppliers\",\n \"inventory.suppliers.create\": \"New Supplier\",\n \"inventory.movements.title\": \"Movements\",\n \"inventory.movements.in\": \"Stock In\",\n \"inventory.movements.out\": \"Stock Out\",\n \"inventory.settings.title\": \"Inventory Settings\",\n\n \"inventory.recipeDetail.cost\": \"Cost\",\n \"inventory.recipeDetail.unitCost\": \"Unit cost\",\n \"inventory.recipeDetail.totalCost\": \"Recipe cost\",\n \"inventory.recipeDetail.costPerYield\": \"Cost per unit produced\",\n \"inventory.recipeDetail.salePrice\": \"Sale price\",\n \"inventory.recipeDetail.cmv\": \"Food cost %\",\n \"inventory.recipeDetail.cmvUnknown\": \"No sale price\",\n \"inventory.recipeDetail.cmvHigh\": \"Above {{threshold}}% — this dish is eating the margin.\",\n\n \"inventory.recipeGaps.title\": \"Not linked to your catalogue\",\n \"inventory.recipeGaps.description\": \"The assistant suggested these but could not match them. Pick the equivalent item or create it.\",\n \"inventory.recipeGaps.produces\": \"Produces:\",\n \"inventory.recipeGaps.unnamed\": \"Unnamed ingredient\",\n \"inventory.recipeGaps.linkFailed\": \"Could not link this item\",\n \"inventory.recipeGaps.createFailed\": \"Could not create the product\",\n\n \"inventory.recipes.entity\": \"Recipe\",\n \"inventory.recipes.colProduct\": \"Product\",\n \"inventory.recipes.colIngredients\": \"Ingredients\",\n \"inventory.recipes.colYield\": \"Yield\",\n \"inventory.recipes.colPrep\": \"Prep\",\n \"inventory.recipes.colCost\": \"Cost\",\n \"inventory.recipes.colSale\": \"Sale\",\n \"inventory.recipes.colCmv\": \"Food cost %\",\n \"inventory.recipes.noSheet\": \"No recipe sheet\",\n \"inventory.recipes.searchPlaceholder\": \"Search menu items...\",\n \"inventory.recipes.newByHand\": \"Fill it in by hand\",\n \"inventory.recipes.newByHandHint\": \"Open the form and enter the ingredients yourself\",\n \"inventory.recipes.aiHint\": \"Describe the dish and get the sheet built with your own ingredients\",\n \"inventory.recipes.askPlaceholder\": \"e.g. recipe for smoked hump with cheese, 400g, serves 3\",\n \"inventory.recipes.askPersona\": \"Recipe sheets\",\n \"inventory.recipes.askPitch\": \"Let's cost your menu\",\n \"inventory.recipes.askDescription\": \"Describe the dish and I build the sheet from the ingredients you already have, with cost and food cost %.\",\n \"inventory.recipes.askSuggestion.0\": \"Build the recipe sheet for the smoked hump with cheese\",\n \"inventory.recipes.askSuggestion.1\": \"Which menu items still have no recipe sheet?\",\n \"inventory.recipes.askSuggestion.2\": \"Which dishes are above 35% food cost?\",\n \"inventory.recipes.loadFailed\": \"Could not load recipe sheets\",\n \"inventory.recipes.retry\": \"Try again\",\n \"inventory.recipeDetail.loadFailed\": \"Could not load this recipe sheet\",\n \"inventory.recipeDetail.retry\": \"Try again\",\n\n \"inventory.nav.counts\": \"Counts\",\n \"inventory.counts.title\": \"Stock counts\",\n \"inventory.counts.entity\": \"Stock count\",\n \"inventory.counts.colReference\": \"Count\",\n \"inventory.counts.colOpened\": \"Opened\",\n \"inventory.counts.colStatus\": \"Status\",\n \"inventory.counts.colProgress\": \"Counted\",\n \"inventory.counts.colDivergent\": \"Divergences\",\n \"inventory.counts.status.open\": \"Open\",\n \"inventory.counts.status.counting\": \"Counting\",\n \"inventory.counts.status.closed\": \"Closed\",\n \"inventory.counts.status.cancelled\": \"Cancelled\",\n \"inventory.counts.progress\": \"{{counted}} of {{total}}\",\n \"inventory.counts.newCount\": \"New count\",\n \"inventory.counts.searchPlaceholder\": \"Search counts...\",\n \"inventory.counts.empty\": \"No counts yet\",\n \"inventory.counts.formTitle\": \"Open a count\",\n \"inventory.counts.formSubtitle\": \"What the system believes is frozen the moment you open it — the variance describes the shelf, not the clock.\",\n \"inventory.counts.location\": \"Stock location\",\n \"inventory.counts.pickLocation\": \"Pick a location\",\n \"inventory.counts.category\": \"Category\",\n \"inventory.counts.allCategories\": \"Every category\",\n \"inventory.counts.reference\": \"Name\",\n \"inventory.counts.referencePlaceholder\": \"e.g. Cold room, end of August\",\n \"inventory.counts.blind\": \"Blind count\",\n \"inventory.counts.blindHint\": \"Hides the system quantity while counting, so you write what is on the shelf instead of confirming what is on the screen.\",\n \"inventory.counts.blindLine\": \"Blind — system quantity hidden\",\n \"inventory.counts.notes\": \"Notes\",\n \"inventory.counts.notesPlaceholder\": \"Anything the next person should know\",\n \"inventory.counts.open\": \"Open the count\",\n \"inventory.counts.opening\": \"Opening...\",\n \"inventory.counts.openFailed\": \"Could not open the count\",\n \"inventory.counts.cancel\": \"Cancel\",\n \"inventory.counts.notFound\": \"Count not found\",\n \"inventory.counts.noItems\": \"This count has no products\",\n \"inventory.counts.systemQty\": \"System:\",\n \"inventory.counts.notCounted\": \"Not counted\",\n \"inventory.counts.counted\": \"Counted\",\n \"inventory.counts.divergent\": \"Divergences\",\n \"inventory.counts.varianceValue\": \"Variance\",\n \"inventory.counts.saveFailed\": \"Could not save this line\",\n \"inventory.counts.close\": \"Close the count\",\n \"inventory.counts.closeTitle\": \"Close the count?\",\n \"inventory.counts.closeDescription\": \"{{divergent}} line(s) differ from the system and will get an adjustment. {{uncounted}} line(s) were never counted and are left exactly as they are.\",\n \"inventory.counts.closeConfirm\": \"Close and adjust\",\n \"inventory.counts.closed\": \"Count closed — {{count}} adjustment(s) recorded\",\n \"inventory.counts.alreadyClosed\": \"This count was already closed\",\n \"inventory.counts.closeFailed\": \"Could not close the count\",\n \"inventory.counts.cancelCount\": \"Cancel count\",\n \"inventory.counts.cancelTitle\": \"Cancel this count?\",\n \"inventory.counts.cancelDescription\": \"The count is filed away and nothing is adjusted. What you typed stays on record.\",\n \"inventory.counts.cancelConfirm\": \"Cancel the count\",\n \"inventory.counts.cancelled\": \"Count cancelled\",\n \"inventory.counts.cancelFailed\": \"Could not cancel the count\",\n \"inventory.counts.adjustmentReason\": \"Stock count {{reference}}\",\n}\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"inventory.dashboard.activeItems\": \"Itens ativos\",\n \"inventory.dashboard.belowMinimum\": \"Abaixo do mínimo\",\n \"inventory.dashboard.entries\": \"Entradas:\",\n \"inventory.dashboard.exits\": \"Saídas:\",\n \"inventory.dashboard.last7Days\": \"Últimos 7 dias\",\n \"inventory.dashboard.lowStock\": \"Estoque Baixo\",\n \"inventory.dashboard.needRestocking\": \"Precisam reposição\",\n \"inventory.dashboard.outOfStock\": \"Sem Estoque\",\n \"inventory.dashboard.quickActions\": \"Ações Rápidas\",\n \"inventory.dashboard.quickActionsDesc\": \"Use a barra lateral para registrar entradas, saídas ou gerenciar produtos.\",\n \"inventory.dashboard.recentActivity\": \"Atividade Recente\",\n \"inventory.dashboard.stockValue\": \"Valor do Estoque\",\n \"inventory.dashboard.totalProducts\": \"Total de Produtos\",\n \"inventory.dashboard.totalValue\": \"Valor total do estoque\",\n \"inventory.history.noMovements\": \"Nenhuma movimentação registrada\",\n \"inventory.history.columnDate\": \"Data\",\n \"inventory.history.columnProduct\": \"Produto\",\n \"inventory.history.columnType\": \"Tipo\",\n \"inventory.history.columnLocation\": \"Local\",\n \"inventory.history.columnQty\": \"Qtd\",\n \"inventory.history.columnTotal\": \"Total\",\n \"inventory.history.newEntry\": \"Nova entrada\",\n \"inventory.history.newExit\": \"Saída\",\n \"inventory.nav.recipes\": \"Receitas\",\n \"registry.suppliers\": \"Fornecedores\",\n \"registry.suppliers.description\": \"De quem você compra\",\n \"registry.product-categories\": \"Categorias\",\n \"registry.product-categories.description\": \"Como o catálogo é agrupado\",\n \"registry.stock-locations\": \"Locais de estoque\",\n \"registry.stock-locations.description\": \"Onde o estoque fica de fato — câmara fria, estoque seco, freezer\",\n \"registry.measurement-units\": \"Unidades de medida\",\n \"registry.measurement-units.description\": \"Como cada item é contado\",\n \"inventory.history.searchPlaceholder\": \"Buscar movimentações...\",\n \"inventory.history.subtitle\": \"Todas as movimentações de estoque\",\n \"inventory.history.title\": \"Histórico de Estoque\",\n \"inventory.nav.dashboard\": \"Painel\",\n \"inventory.nav.entry\": \"Entrada\",\n \"inventory.nav.exit\": \"Saída\",\n \"inventory.nav.history\": \"Histórico\",\n \"inventory.nav.list\": \"Lista\",\n \"inventory.nav.new\": \"Novo\",\n \"inventory.nav.products\": \"Produtos\",\n \"inventory.nav.stock\": \"Estoque\",\n \"inventory.page.newProduct\": \"Novo Produto\",\n \"inventory.page.newProductDesc\": \"Adicionar um produto ao seu catálogo\",\n \"inventory.page.settingsSubtitle\": \"Preferências, fornecedores, categorias e unidades\",\n \"inventory.page.settingsTitle\": \"Configurações de Estoque\",\n \"inventory.page.stockEntry\": \"Entrada de Estoque\",\n \"inventory.page.stockEntryDesc\": \"Registrar mercadorias recebidas\",\n \"inventory.page.stockExit\": \"Saída de Estoque\",\n \"inventory.page.stockExitDesc\": \"Registrar mercadorias usadas ou vendidas\",\n \"inventory.recipeDetail.active\": \"Ativa\",\n \"inventory.recipeDetail.backToList\": \"Voltar à lista\",\n \"inventory.recipeDetail.inactive\": \"Inativa\",\n \"inventory.recipeDetail.ingredientCount\": \"Ingredientes\",\n \"inventory.recipeDetail.ingredientsTitle\": \"Ingredientes\",\n \"inventory.recipeDetail.instructions\": \"Instruções\",\n \"inventory.recipeDetail.noIngredients\": \"Nenhum ingrediente definido\",\n \"inventory.recipeDetail.notFound\": \"Receita não encontrada\",\n \"inventory.recipeDetail.prepTime\": \"Tempo de preparo\",\n \"inventory.recipeDetail.produces\": \"Produz\",\n \"inventory.recipeDetail.recipes\": \"Receitas\",\n \"inventory.recipeDetail.yield\": \"Rendimento\",\n \"inventory.recipes.createFirst\": \"Crie sua primeira receita\",\n \"inventory.recipes.ingredients\": \"Ingredientes\",\n \"inventory.recipes.newRecipe\": \"Nova Receita\",\n \"inventory.recipes.noRecipes\": \"Nenhuma receita ainda\",\n \"inventory.recipes.produces\": \"Produz:\",\n \"inventory.recipes.productionFormulas\": \"{{count}} fórmulas de produção\",\n \"inventory.recipes.recipesDesc\": \"Receitas definem como produzir produtos a partir de ingredientes\",\n \"inventory.recipes.title\": \"Receitas\",\n \"inventory.recipes.yield\": \"Rendimento\",\n \"inventory.stock.additionalDetails\": \"Detalhes adicionais (opcional)\",\n \"inventory.stock.adjustmentDesc\": \"Correção de contagem\",\n \"inventory.stock.adjustmentLabel\": \"Ajuste\",\n \"inventory.stock.back\": \"Voltar\",\n \"inventory.stock.batchNumber\": \"Número do Lote\",\n \"inventory.stock.currentStock\": \"Estoque Atual\",\n \"inventory.stock.destination\": \"Destino\",\n \"inventory.stock.document\": \"Documento\",\n \"inventory.stock.documentNumber\": \"Número do Documento\",\n \"inventory.stock.entry\": \"Entrada de Estoque\",\n \"inventory.stock.entryDesc\": \"Recebimento de mercadorias\",\n \"inventory.stock.entryLabel\": \"Entrada\",\n \"inventory.stock.exit\": \"Saída de Estoque\",\n \"inventory.stock.exitDesc\": \"Uso ou venda\",\n \"inventory.stock.exitLabel\": \"Saída\",\n \"inventory.stock.expirationDate\": \"Data de Validade\",\n \"inventory.stock.fromLocation\": \"Local de Origem\",\n \"inventory.stock.locationLabel\": \"Local\",\n \"inventory.stock.lossDesc\": \"Desperdício ou dano\",\n \"inventory.stock.lossLabel\": \"Perda\",\n \"inventory.stock.movement\": \"Movimentação de Estoque\",\n \"inventory.stock.movementDetails\": \"Detalhes da Movimentação\",\n \"inventory.stock.movementType\": \"Tipo de movimentação\",\n \"inventory.stock.next\": \"Próximo\",\n \"inventory.stock.notes\": \"Observações\",\n \"inventory.stock.product\": \"Produto\",\n \"inventory.stock.quantity\": \"Quantidade *\",\n \"inventory.stock.quantityLabel\": \"Quantidade\",\n \"inventory.stock.reason\": \"Motivo *\",\n \"inventory.stock.reasonLabel\": \"Motivo\",\n \"inventory.stock.recordMovement\": \"Registrar Movimentação\",\n \"inventory.stock.recorded\": \"Registrado\",\n \"inventory.stock.recording\": \"Registrando...\",\n \"inventory.stock.searchProduct\": \"Buscar por nome, SKU ou código de barras...\",\n \"inventory.stock.stepOf\": \"Etapa {{step}} de 3\",\n \"inventory.stock.supplier\": \"Fornecedor\",\n \"inventory.stock.toLocation\": \"Local de Destino *\",\n \"inventory.stock.total\": \"Total\",\n \"inventory.stock.totalCost\": \"Custo Total\",\n \"inventory.stock.transferDesc\": \"Entre locais\",\n \"inventory.stock.transferLabel\": \"Transferência\",\n \"inventory.stock.unitCost\": \"Custo Unitário\",\n \"inventory.stock.unitCostLabel\": \"Custo Unitário\",\n \"inventory.stock.searchSupplier\": \"Buscar fornecedor...\",\n \"inventory.stock.noSuppliers\": \"Nenhum fornecedor cadastrado\",\n \"inventory.productDetail.stockTab\": \"Estoque\",\n \"inventory.productDetail.positionsTitle\": \"Estoque por local\",\n \"inventory.productDetail.onHand\": \"Em estoque\",\n \"inventory.productDetail.noPositions\": \"Sem estoque em nenhum local\",\n \"inventory.productDetail.historyTitle\": \"Movimentação\",\n \"inventory.productDetail.undoLast\": \"Desfazer último movimento\",\n \"inventory.productDetail.undoTitle\": \"Desfazer o último movimento?\",\n \"inventory.productDetail.undoDescription\": \"{{type}} de {{quantity}} em {{date}} sai do histórico, e o estoque que ele moveu volta.\",\n \"inventory.productDetail.undoConfirm\": \"Desfazer\",\n \"inventory.productDetail.undone\": \"Movimento desfeito\",\n \"inventory.productDetail.undoFailed\": \"Não foi possível desfazer o movimento\",\n \"inventory.productDetail.notFound\": \"Produto não encontrado\",\n \"inventory.productDetail.backToList\": \"Voltar para produtos\",\n \"inventory.onboarding.welcome\": \"Bem-vindo ao Estoque\",\n \"inventory.onboarding.description\": \"Acompanhe produtos, gerencie níveis de estoque e monitore movimentações do seu negócio.\",\n \"inventory.onboarding.skip\": \"Pular configuração\",\n \"inventory.onboarding.getStarted\": \"Começar\",\n \"inventory.onboarding.units.title\": \"Unidades de Medida\",\n \"inventory.onboarding.units.description\": \"Unidades padrão (Unidade, Caixa, Kg, L, etc.) estão prontas. Personalize-as a qualquer momento em Configurações.\",\n \"inventory.onboarding.locations.title\": \"Locais de Estoque\",\n \"inventory.onboarding.locations.description\": \"Um local de armazenamento padrão foi criado. Adicione mais para controle multi-local.\",\n \"inventory.onboarding.start\": \"Começar a usar Estoque\",\n \"inventory.onboarding.preparing\": \"Preparando estoque...\",\n \"inventory.onboarding.setupError\": \"Não foi possível preparar as unidades e o local padrão. Tente novamente.\",\n \"inventory.quickActions.newProduct\": \"Novo Produto\",\n \"inventory.quickActions.newProductDesc\": \"Adicionar um produto ao catálogo\",\n \"inventory.quickActions.stockEntry\": \"Entrada de Estoque\",\n \"inventory.quickActions.stockEntryDesc\": \"Registrar mercadorias recebidas\",\n \"inventory.quickActions.stockExit\": \"Saída de Estoque\",\n \"inventory.quickActions.stockExitDesc\": \"Registrar mercadorias usadas ou vendidas\",\n \"inventory.settingsPage.title\": \"Configurações de Estoque\",\n \"inventory.settingsPage.subtitle\": \"Gerenciar unidades, categorias e locais de estoque\",\n \"inventory.settings.stockManagement\": \"Gestão de Estoque\",\n \"inventory.settings.stockManagementDesc\": \"Como os níveis de estoque são rastreados\",\n \"inventory.settings.lowStockAlerts\": \"Alertas de estoque baixo\",\n \"inventory.settings.lowStockAlertsDesc\": \"Mostrar avisos quando produtos ficarem abaixo da quantidade mínima\",\n \"inventory.settings.requireReason\": \"Exigir motivo para ajustes\",\n \"inventory.settings.requireReasonDesc\": \"Tornar obrigatório o motivo para ajustes e perdas de estoque\",\n \"inventory.settings.autoDeduct\": \"Auto-deduzir no serviço\",\n \"inventory.settings.autoDeductDesc\": \"Deduzir automaticamente produtos quando um serviço é executado\",\n \"inventory.settings.products\": \"Produtos\",\n \"inventory.settings.productsDesc\": \"Comportamento do catálogo de produtos\",\n \"inventory.settings.requireSku\": \"Exigir SKU\",\n \"inventory.settings.requireSkuDesc\": \"Tornar SKU obrigatório ao criar produtos\",\n \"inventory.settings.allowNegative\": \"Permitir estoque negativo\",\n \"inventory.settings.allowNegativeDesc\": \"Permitir que quantidades de estoque fiquem abaixo de zero\",\n \"inventory.settings.notifications\": \"Notificações\",\n \"inventory.settings.notificationsDesc\": \"Alertas e lembretes\",\n \"inventory.settings.lowStockEmail\": \"Alertas de estoque baixo por e-mail\",\n \"inventory.settings.lowStockEmailDesc\": \"Enviar e-mail quando produtos atingirem a quantidade mínima\",\n \"inventory.settings.expiryWarnings\": \"Avisos de validade\",\n \"inventory.settings.expiryWarningsDesc\": \"Alertar antes de produtos vencerem (rastreamento de lotes)\",\n \"inventory.productForm.newProduct\": \"Novo Produto\",\n \"inventory.productForm.editProduct\": \"Editar Produto\",\n \"inventory.productForm.updateDetails\": \"Atualizar detalhes do produto\",\n \"inventory.productForm.addToCatalog\": \"Adicionar um produto ao seu catálogo\",\n \"inventory.productForm.cancel\": \"Cancelar\",\n \"inventory.productForm.save\": \"Salvar\",\n \"inventory.productForm.saving\": \"Salvando...\",\n \"inventory.productForm.generalInfo\": \"Informações Gerais\",\n \"inventory.productForm.name\": \"Nome\",\n \"inventory.productForm.namePlaceholder\": \"Nome do produto\",\n \"inventory.productForm.brand\": \"Marca\",\n \"inventory.productForm.brandPlaceholder\": \"Nome da marca\",\n \"inventory.productForm.sku\": \"SKU\",\n \"inventory.productForm.skuPlaceholder\": \"Código interno\",\n \"inventory.productForm.barcode\": \"Código de Barras\",\n \"inventory.productForm.barcodePlaceholder\": \"EAN / UPC\",\n \"inventory.productForm.description\": \"Descrição\",\n \"inventory.productForm.descriptionPlaceholder\": \"Informações adicionais sobre o produto\",\n \"inventory.productForm.classification\": \"Classificação\",\n \"inventory.productForm.classificationDesc\": \"Como este produto é usado no seu negócio\",\n \"inventory.productForm.typeIngredient\": \"Matéria-prima usada na produção ou serviços\",\n \"inventory.productForm.typeSale\": \"Vendido diretamente aos clientes\",\n \"inventory.productForm.typeIntermediate\": \"Produzido internamente a partir de outros itens\",\n \"inventory.productForm.typeAsset\": \"Ativo fixo para controle patrimonial\",\n \"inventory.productForm.pricing\": \"Preços\",\n \"inventory.productForm.costPrice\": \"Preço de Custo\",\n \"inventory.productForm.salePrice\": \"Preço de Venda\",\n \"inventory.productForm.margin\": \"Margem\",\n \"inventory.productForm.stockLevels\": \"Níveis de Estoque\",\n \"inventory.productForm.stockLevelsDesc\": \"Limites mínimo e máximo para alertas\",\n \"inventory.productForm.minQuantity\": \"Quantidade Mínima\",\n \"inventory.productForm.minQuantityHint\": \"Alertar quando o estoque ficar abaixo deste valor\",\n \"inventory.productForm.maxQuantity\": \"Quantidade Máxima\",\n \"inventory.productForm.maxQuantityHint\": \"Capacidade máxima para este produto\",\n \"inventory.productForm.optional\": \"Opcional\",\n \"inventory.productForm.organization\": \"Organização\",\n \"inventory.productForm.organizationDesc\": \"Categoria, unidade, fornecedor e local padrão de estoque\",\n \"inventory.productForm.category\": \"Categoria\",\n \"inventory.productForm.measurementUnit\": \"Unidade de medida\",\n \"inventory.productForm.measurementUnitHint\": \"Como este item é contado no estoque\",\n \"inventory.productForm.supplier\": \"Fornecedor padrão\",\n \"inventory.productForm.defaultLocation\": \"Local padrão\",\n \"inventory.movementType.entry\": \"Entrada\",\n \"inventory.movementType.exit\": \"Saída\",\n \"inventory.movementType.adjustment\": \"Ajuste\",\n \"inventory.movementType.transfer\": \"Transferência\",\n \"inventory.movementType.loss\": \"Perda\",\n \"inventory.recipeForm.group\": \"Etapa\",\n \"inventory.recipeForm.ungrouped\": \"Sem etapa\",\n \"inventory.productList.bulkActivate\": \"Ativar\",\n \"inventory.productList.bulkActivated\": \"{{count}} produto(s) ativado(s)\",\n \"inventory.productList.bulkDeactivate\": \"Desativar\",\n \"inventory.productList.bulkDeactivated\": \"{{count}} produto(s) desativado(s)\",\n \"inventory.productList.bulkFailed\": \"{{count}} produto(s) não puderam ser atualizados\",\n \"inventory.productList.bulkNothingToDo\": \"Os produtos selecionados já estão nesse estado.\",\n \"inventory.productList.filterActive\": \"Ativos\",\n \"inventory.productList.filterAllStatuses\": \"Ativos e inativos\",\n \"inventory.productList.filterInactive\": \"Inativos\",\n \"inventory.productList.filterStatus\": \"Situação\",\n \"inventory.productList.inactive\": \"Inativo\",\n \"inventory.productList.title\": \"Produtos\",\n \"inventory.productList.subtitle\": \"{{count}} produtos\",\n \"inventory.productList.product\": \"Produto\",\n \"inventory.productList.type\": \"Tipo\",\n \"inventory.productList.stock\": \"Estoque\",\n \"inventory.productList.cost\": \"Custo\",\n \"inventory.productList.value\": \"Valor\",\n \"inventory.productList.searchPlaceholder\": \"Buscar produtos...\",\n 'inventory.productList.aiHint': 'Descreva o produto e eu cadastro.',\n 'inventory.productList.askPlaceholder': 'Descreva o produto…',\n 'inventory.productList.askPersona': 'Cadastro de produtos',\n 'inventory.productList.askPitch': 'Diga o produto que você quer cadastrar.',\n 'inventory.productList.askDescription': 'Nome, preço, custo, SKU, tipo — diga o que souber, do jeito que falar, e eu preencho o resto com o que faz sentido. Você confere antes de salvar.',\n 'inventory.productList.askSuggestion.0': 'Camiseta preta P/M/G, R$ 79, custo R$ 28',\n 'inventory.productList.askSuggestion.1': 'Cadastre 5 produtos de exemplo para eu testar a loja',\n 'inventory.productList.askSuggestion.2': 'Um combo com os dois itens mais vendidos',\n \"inventory.productList.newProduct\": \"Novo Produto\",\n \"inventory.productList.empty\": \"Nenhum produto ainda\",\n \"inventory.productList.createFirst\": \"Crie seu primeiro produto\",\n \"inventory.stock.unknownProduct\": \"Produto Desconhecido\",\n \"inventory.stock.reasonLossPlaceholder\": \"ex. Vencido, danificado\",\n \"inventory.stock.reasonAdjustPlaceholder\": \"ex. Correção de contagem física\",\n \"inventory.stock.documentPlaceholder\": \"Nota fiscal, recibo, PO...\",\n \"inventory.stock.batchPlaceholder\": \"ex. LOT001\",\n \"inventory.stock.notesPlaceholder\": \"Observações adicionais...\",\n \"inventory.recipeDetail.loading\": \"Carregando...\",\n \"inventory.recipeDetail.ingredient\": \"Ingrediente\",\n \"inventory.recipeDetail.quantity\": \"Quantidade\",\n \"inventory.recipeDetail.unit\": \"Unidade\",\n \"inventory.recipeDetail.notes\": \"Observações\",\n \"inventory.recipeDetail.created\": \"Criado\",\n \"inventory.recipeDetail.updated\": \"Atualizado\",\n \"inventory.recipeForm.newRecipe\": \"Nova Receita\",\n \"inventory.recipeForm.subtitle\": \"Definir uma fórmula de produção\",\n \"inventory.recipeForm.cancel\": \"Cancelar\",\n \"inventory.recipeForm.saveRecipe\": \"Salvar Receita\",\n \"inventory.recipeForm.saving\": \"Salvando...\",\n \"inventory.recipeForm.recipeDetails\": \"Detalhes da Receita\",\n \"inventory.recipeForm.recipeName\": \"Nome da Receita\",\n \"inventory.recipeForm.recipeNamePlaceholder\": \"ex. Molho de Tomate\",\n \"inventory.recipeForm.description\": \"Descrição\",\n \"inventory.recipeForm.descriptionPlaceholder\": \"Breve descrição...\",\n \"inventory.recipeForm.produces\": \"Produz (Produto)\",\n \"inventory.recipeForm.searchProduct\": \"Buscar produto...\",\n \"inventory.recipeForm.createProduct\": \"Criar produto\",\n \"inventory.recipeForm.yieldQuantity\": \"Quantidade de Rendimento\",\n \"inventory.recipeForm.prepTime\": \"Tempo de Preparo (min)\",\n \"inventory.recipeForm.instructions\": \"Instruções\",\n \"inventory.recipeForm.instructionsPlaceholder\": \"Instruções de preparo passo a passo...\",\n \"inventory.recipeForm.ingredients\": \"Ingredientes\",\n \"inventory.recipeForm.addIngredient\": \"Adicionar Ingrediente\",\n \"inventory.recipeForm.noIngredients\": \"Nenhum ingrediente adicionado\",\n \"inventory.recipeForm.addFirstIngredient\": \"Adicione seu primeiro ingrediente\",\n \"inventory.recipeForm.ingredient\": \"Ingrediente\",\n \"inventory.recipeForm.quantity\": \"Quantidade\",\n \"inventory.recipeForm.notes\": \"Observações\",\n \"inventory.recipeForm.searchIngredient\": \"Buscar ingrediente...\",\n \"inventory.recipeForm.createIngredient\": \"Criar ingrediente\",\n \"inventory.recipeForm.notesPlaceholder\": \"ex. picado, fresco\",\n \"inventory.recipeForm.ingredientsConfigured\": \"{{configured}} de {{total}} ingredientes configurados\",\n \"inventory.title\": \"Estoque\",\n \"inventory.stock.title\": \"Estoque\",\n \"inventory.stock.minStock\": \"Estoque Mín.\",\n \"inventory.stock.adjust\": \"Ajustar Estoque\",\n \"inventory.stock.lowStock\": \"Estoque Baixo\",\n \"inventory.products.title\": \"Produtos\",\n \"inventory.products.create\": \"Novo Produto\",\n \"inventory.recipes.create\": \"Nova Receita\",\n \"inventory.recipes.addIngredient\": \"Adicionar Ingrediente\",\n \"inventory.recipes.cost\": \"Custo\",\n \"inventory.recipes.loading\": \"Carregando...\",\n \"inventory.suppliers.title\": \"Fornecedores\",\n \"inventory.suppliers.create\": \"Novo Fornecedor\",\n \"inventory.movements.title\": \"Movimentações\",\n \"inventory.movements.in\": \"Entrada\",\n \"inventory.movements.out\": \"Saída\",\n \"inventory.settings.title\": \"Configurações de Estoque\",\n\n \"inventory.recipeDetail.cost\": \"Custo\",\n \"inventory.recipeDetail.unitCost\": \"Custo unitário\",\n \"inventory.recipeDetail.totalCost\": \"Custo da ficha\",\n \"inventory.recipeDetail.costPerYield\": \"Custo por unidade produzida\",\n \"inventory.recipeDetail.salePrice\": \"Preço de venda\",\n \"inventory.recipeDetail.cmv\": \"CMV\",\n \"inventory.recipeDetail.cmvUnknown\": \"Sem preço de venda\",\n \"inventory.recipeDetail.cmvHigh\": \"Acima de {{threshold}}% — este prato está comendo a margem.\",\n\n \"inventory.recipeGaps.title\": \"Falta ligar ao seu catálogo\",\n \"inventory.recipeGaps.description\": \"A assistente sugeriu estes itens mas não achou equivalente. Escolha o insumo certo ou cadastre.\",\n \"inventory.recipeGaps.produces\": \"Produz:\",\n \"inventory.recipeGaps.unnamed\": \"Ingrediente sem nome\",\n \"inventory.recipeGaps.linkFailed\": \"Não foi possível ligar este item\",\n \"inventory.recipeGaps.createFailed\": \"Não foi possível cadastrar o produto\",\n\n \"inventory.recipes.entity\": \"Ficha técnica\",\n \"inventory.recipes.colProduct\": \"Produto\",\n \"inventory.recipes.colIngredients\": \"Insumos\",\n \"inventory.recipes.colYield\": \"Rendimento\",\n \"inventory.recipes.colPrep\": \"Preparo\",\n \"inventory.recipes.colCost\": \"Custo\",\n \"inventory.recipes.colSale\": \"Venda\",\n \"inventory.recipes.colCmv\": \"CMV\",\n \"inventory.recipes.noSheet\": \"Sem ficha técnica\",\n \"inventory.recipes.searchPlaceholder\": \"Buscar item do cardápio...\",\n \"inventory.recipes.newByHand\": \"Preencher à mão\",\n \"inventory.recipes.newByHandHint\": \"Abrir o formulário e lançar os insumos você mesmo\",\n \"inventory.recipes.aiHint\": \"Descreva o prato e receba a ficha montada com os seus insumos\",\n \"inventory.recipes.askPlaceholder\": \"ex. ficha técnica do cupim defumado com queijo, 400g, serve 3\",\n \"inventory.recipes.askPersona\": \"Fichas técnicas\",\n \"inventory.recipes.askPitch\": \"Vamos custear o seu cardápio\",\n \"inventory.recipes.askDescription\": \"Descreva o prato que eu monto a ficha com os insumos que você já tem, com custo e CMV.\",\n \"inventory.recipes.askSuggestion.0\": \"Monte a ficha técnica do cupim defumado com queijo\",\n \"inventory.recipes.askSuggestion.1\": \"Quais itens do cardápio ainda não têm ficha técnica?\",\n \"inventory.recipes.askSuggestion.2\": \"Quais pratos estão acima de 35% de CMV?\",\n \"inventory.recipes.loadFailed\": \"Não foi possível carregar as fichas técnicas\",\n \"inventory.recipes.retry\": \"Tentar novamente\",\n \"inventory.recipeDetail.loadFailed\": \"Não foi possível carregar esta ficha técnica\",\n \"inventory.recipeDetail.retry\": \"Tentar novamente\",\n\n \"inventory.nav.counts\": \"Contagens\",\n \"inventory.counts.title\": \"Contagens de estoque\",\n \"inventory.counts.entity\": \"Contagem\",\n \"inventory.counts.colReference\": \"Contagem\",\n \"inventory.counts.colOpened\": \"Aberta em\",\n \"inventory.counts.colStatus\": \"Situação\",\n \"inventory.counts.colProgress\": \"Contados\",\n \"inventory.counts.colDivergent\": \"Divergências\",\n \"inventory.counts.status.open\": \"Aberta\",\n \"inventory.counts.status.counting\": \"Contando\",\n \"inventory.counts.status.closed\": \"Fechada\",\n \"inventory.counts.status.cancelled\": \"Cancelada\",\n \"inventory.counts.progress\": \"{{counted}} de {{total}}\",\n \"inventory.counts.newCount\": \"Nova contagem\",\n \"inventory.counts.searchPlaceholder\": \"Buscar contagem...\",\n \"inventory.counts.empty\": \"Nenhuma contagem ainda\",\n \"inventory.counts.formTitle\": \"Abrir uma contagem\",\n \"inventory.counts.formSubtitle\": \"O que o sistema acredita é congelado na hora em que você abre — a variação fala da prateleira, não do relógio.\",\n \"inventory.counts.location\": \"Local de estoque\",\n \"inventory.counts.pickLocation\": \"Escolha um local\",\n \"inventory.counts.category\": \"Categoria\",\n \"inventory.counts.allCategories\": \"Todas as categorias\",\n \"inventory.counts.reference\": \"Nome\",\n \"inventory.counts.referencePlaceholder\": \"ex. Câmara fria, fim de agosto\",\n \"inventory.counts.blind\": \"Contagem cega\",\n \"inventory.counts.blindHint\": \"Esconde a quantidade do sistema enquanto você conta, para escrever o que está na prateleira em vez de confirmar o que está na tela.\",\n \"inventory.counts.blindLine\": \"Cega — quantidade do sistema oculta\",\n \"inventory.counts.notes\": \"Observações\",\n \"inventory.counts.notesPlaceholder\": \"O que a próxima pessoa precisa saber\",\n \"inventory.counts.open\": \"Abrir a contagem\",\n \"inventory.counts.opening\": \"Abrindo...\",\n \"inventory.counts.openFailed\": \"Não foi possível abrir a contagem\",\n \"inventory.counts.cancel\": \"Cancelar\",\n \"inventory.counts.notFound\": \"Contagem não encontrada\",\n \"inventory.counts.noItems\": \"Esta contagem não tem produtos\",\n \"inventory.counts.systemQty\": \"Sistema:\",\n \"inventory.counts.notCounted\": \"Não contado\",\n \"inventory.counts.counted\": \"Contados\",\n \"inventory.counts.divergent\": \"Divergências\",\n \"inventory.counts.varianceValue\": \"Variação\",\n \"inventory.counts.saveFailed\": \"Não foi possível salvar esta linha\",\n \"inventory.counts.close\": \"Fechar a contagem\",\n \"inventory.counts.closeTitle\": \"Fechar a contagem?\",\n \"inventory.counts.closeDescription\": \"{{divergent}} linha(s) divergem do sistema e vão receber um ajuste. {{uncounted}} linha(s) ninguém contou e ficam exatamente como estão.\",\n \"inventory.counts.closeConfirm\": \"Fechar e ajustar\",\n \"inventory.counts.closed\": \"Contagem fechada — {{count}} ajuste(s) lançado(s)\",\n \"inventory.counts.alreadyClosed\": \"Esta contagem já estava fechada\",\n \"inventory.counts.closeFailed\": \"Não foi possível fechar a contagem\",\n \"inventory.counts.cancelCount\": \"Cancelar contagem\",\n \"inventory.counts.cancelTitle\": \"Cancelar esta contagem?\",\n \"inventory.counts.cancelDescription\": \"A contagem é arquivada e nada é ajustado. O que você digitou fica registrado.\",\n \"inventory.counts.cancelConfirm\": \"Cancelar a contagem\",\n \"inventory.counts.cancelled\": \"Contagem cancelada\",\n \"inventory.counts.cancelFailed\": \"Não foi possível cancelar a contagem\",\n \"inventory.counts.adjustmentReason\": \"Contagem de estoque {{reference}}\",\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const inventoryLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","// AUTO-GENERATED from 000_plg_rename.sql, 001_inventory_base.sql, 002_recipes.sql, 003_measurement_units.sql, 004_stock_movement_view.sql, 005_product_details.sql, 006_stock_position_slots.sql, 007_recipe_groups.sql, 008_rls_policies.sql, 009_agent_rpcs.sql, 010_stock_counts.sql, 011_scaffold.sql, 012_inventory_core_contract.sql, 013_inventory_units.sql, 014_inventory_positions_and_views.sql, 015_inventory_rpcs.sql, 016_inventory_legacy_backfill.sql, 017_reservation_one_per_source.sql, 018_scope_locality.sql, 019_the_stock_mirror_asks_first.sql, 020_stock_reacts_to_a_completed_sale.sql, 021_the_movement_writes_the_archetype.sql, 022_the_count_tables_join_the_template.sql, 023_product_images_are_registered_files.sql, 024_restaurant_order_stock_events.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_PLG_RENAME = `-- 000_plg_rename.sql — rename legacy inventory tables to plg_inventory_* for pools\n-- provisioned before the industry-pool rename. Guarded: fires only when the legacy\n-- name exists and the target does not, so fresh pools skip every branch.\nDO $$\nBEGIN\n IF to_regclass('public.stock_locations') IS NOT NULL AND to_regclass('public.plg_inventory_stock_locations') IS NULL THEN\n ALTER TABLE public.stock_locations RENAME TO plg_inventory_stock_locations;\n END IF;\n IF to_regclass('public.stock_movements') IS NOT NULL AND to_regclass('public.plg_inventory_stock_movements') IS NULL THEN\n ALTER TABLE public.stock_movements RENAME TO plg_inventory_stock_movements;\n END IF;\n IF to_regclass('public.stock_positions') IS NOT NULL AND to_regclass('public.plg_inventory_stock_positions') IS NULL THEN\n ALTER TABLE public.stock_positions RENAME TO plg_inventory_stock_positions;\n END IF;\n IF to_regclass('public.recipes') IS NOT NULL AND to_regclass('public.plg_inventory_recipes') IS NULL THEN\n ALTER TABLE public.recipes RENAME TO plg_inventory_recipes;\n END IF;\n IF to_regclass('public.recipe_ingredients') IS NOT NULL AND to_regclass('public.plg_inventory_recipe_ingredients') IS NULL THEN\n ALTER TABLE public.recipe_ingredients RENAME TO plg_inventory_recipe_ingredients;\n END IF;\n IF to_regclass('public.measurement_units') IS NOT NULL AND to_regclass('public.plg_inventory_measurement_units') IS NULL THEN\n ALTER TABLE public.measurement_units RENAME TO plg_inventory_measurement_units;\n END IF;\n IF to_regclass('public.product_categories') IS NOT NULL AND to_regclass('public.plg_inventory_product_categories') IS NULL THEN\n ALTER TABLE public.product_categories RENAME TO plg_inventory_product_categories;\n END IF;\nEND $$;\n`\n\nexport const MIGRATION_001_INVENTORY_BASE = `-- Inventory Plugin: Base Tables\n-- Products use public.products archetype directly\n-- These are plugin-specific extension tables\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_categories (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n name text NOT NULL,\n parent_id uuid REFERENCES public.plg_inventory_product_categories(id),\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_product_categories ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_product_categories_tenant ON public.plg_inventory_product_categories(tenant_id);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_stock_locations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n name text NOT NULL,\n description text,\n is_active boolean NOT NULL DEFAULT true,\n unit_id uuid,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_stock_locations ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_locations_tenant ON public.plg_inventory_stock_locations(tenant_id);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_stock_movements (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n product_id uuid NOT NULL REFERENCES public.products(id),\n quantity numeric(14,4) NOT NULL,\n movement_type text NOT NULL,\n unit_cost numeric(14,2) DEFAULT 0,\n total_cost numeric(14,2) DEFAULT 0,\n stock_location_id uuid REFERENCES public.plg_inventory_stock_locations(id),\n destination_location_id uuid REFERENCES public.plg_inventory_stock_locations(id),\n supplier_id uuid REFERENCES public.people(id),\n document_number text,\n reason text,\n notes text,\n movement_date date NOT NULL DEFAULT CURRENT_DATE,\n user_id uuid,\n batch_number text,\n expiration_date date,\n metadata jsonb DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_stock_movements ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_movements_tenant ON public.plg_inventory_stock_movements(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_movements_product ON public.plg_inventory_stock_movements(product_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_movements_date ON public.plg_inventory_stock_movements(tenant_id, movement_date);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_stock_positions (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n product_id uuid NOT NULL REFERENCES public.products(id),\n quantity numeric(14,4) NOT NULL,\n unit_cost numeric(14,2) DEFAULT 0,\n stock_location_id uuid REFERENCES public.plg_inventory_stock_locations(id),\n batch_number text,\n expiration_date date,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_stock_positions ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_positions_tenant ON public.plg_inventory_stock_positions(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_stock_positions_product ON public.plg_inventory_stock_positions(product_id);\n`\n\nexport const MIGRATION_002_RECIPES = `-- Inventory Plugin: Recipes & Technical Specs\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_recipes (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n name text NOT NULL,\n description text,\n product_id uuid REFERENCES public.products(id),\n yield_quantity numeric(14,4) DEFAULT 1,\n yield_unit_id uuid,\n preparation_time_minutes integer,\n instructions text,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_recipes ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipes_tenant ON public.plg_inventory_recipes(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipes_product ON public.plg_inventory_recipes(product_id);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_recipe_ingredients (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n recipe_id uuid NOT NULL REFERENCES public.plg_inventory_recipes(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n product_id uuid NOT NULL REFERENCES public.products(id),\n quantity numeric(14,4) NOT NULL,\n unit_id uuid,\n display_order integer DEFAULT 0,\n notes text,\n created_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_recipe_ingredients ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipe_ingredients_tenant ON public.plg_inventory_recipe_ingredients(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipe_ingredients_recipe ON public.plg_inventory_recipe_ingredients(recipe_id);\n`\n\nexport const MIGRATION_003_MEASUREMENT_UNITS = `-- Inventory Plugin: Measurement Units\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_measurement_units (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n name text NOT NULL,\n abbreviation text NOT NULL,\n is_active boolean NOT NULL DEFAULT true,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_measurement_units ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_measurement_units_tenant ON public.plg_inventory_measurement_units(tenant_id);\n`\n\nexport const MIGRATION_004_STOCK_MOVEMENT_VIEW = `-- ============================================================================\n-- 011_stock_movement_view.sql — v_stock_movements was reading every tenant.\n--\n-- \\`plugin-inventory/src/data/supabase.ts\\` reads \\`public.v_stock_movements\\` for\n-- the whole movement history — it is what the Histórico screen renders. That\n-- view is defined NOWHERE in this repo. It exists on cluster-restaurant-br-01\n-- because a legacy Supabase-CLI chain created it by hand, and it was created\n-- without \\`security_invoker\\`.\n--\n-- A view runs with the privileges of its OWNER unless created\n-- \\`WITH (security_invoker = true)\\`. The hand-applied view is owned by\n-- \\`postgres\\`, who also owns plg_inventory_stock_movements, and a table owner is\n-- exempt from that table's RLS unless the table carries FORCE ROW LEVEL\n-- SECURITY — which it does not. \\`authenticated\\` holds SELECT on the view.\n--\n-- So on a shared industry pool, any signed-in user of ANY tenant could\n--\n-- SELECT * FROM public.v_stock_movements;\n--\n-- and read every tenant's stock ledger — quantities, unit costs, suppliers.\n--\n-- packages/db/migrations/050_view_invoker.sql exists to close exactly this\n-- class of hole and names nine views. It could not name this one: the view is\n-- in no migration, so nobody auditing the tree knew it existed. This file is\n-- the plugin carrying the fix forward, as 050's header asks each plugin to do.\n--\n-- WHY DROP AND RECREATE RATHER THAN CREATE OR REPLACE. \\`CREATE OR REPLACE VIEW\\`\n-- refuses to change a column's name, type or position. The hand-applied\n-- definitions differ across pools — resto-saas's quarantined\n-- \\`supabase/migrations.legacy/20260201000018_v_stock_movements_locations.sql\\`\n-- still selects from \\`saas_core.products\\` and the pre-rename\n-- \\`public.stock_movements\\`. A replace would fail on whichever pool disagrees.\n-- DROP without CASCADE is deliberate: if something depends on this view we want\n-- to hear about it, not to silently drop it too.\n-- ============================================================================\n\nDROP VIEW IF EXISTS public.v_stock_movements;\n\nCREATE VIEW public.v_stock_movements\nWITH (security_invoker = true) AS\n SELECT\n sm.id,\n sm.tenant_id,\n sm.product_id,\n sm.quantity,\n sm.movement_type,\n sm.unit_cost,\n sm.total_cost,\n sm.stock_location_id,\n sm.destination_location_id,\n sm.supplier_id,\n sm.document_number,\n sm.reason,\n sm.notes,\n sm.movement_date,\n sm.user_id,\n sm.batch_number,\n sm.expiration_date,\n sm.metadata,\n sm.created_at,\n p.name AS product_name,\n p.sku AS product_sku,\n sl.name AS stock_location_name,\n dl.name AS destination_location_name\n FROM public.plg_inventory_stock_movements sm\n LEFT JOIN public.products p ON p.id = sm.product_id\n LEFT JOIN public.plg_inventory_stock_locations sl ON sl.id = sm.stock_location_id\n LEFT JOIN public.plg_inventory_stock_locations dl ON dl.id = sm.destination_location_id;\n\nGRANT SELECT ON public.v_stock_movements TO authenticated;\n\nNOTIFY pgrst, 'reload schema';\n\n-- What changes on screen: a Histórico that was quietly listing other tenants'\n-- movements now lists only its own. That is a shorter list and it is the\n-- correct one.\n`\n\nexport const MIGRATION_005_PRODUCT_DETAILS = `-- ============================================================================\n-- 012_product_details.sql — the product attributes the plugin kept dropping.\n--\n-- A Product in this plugin is the spine archetype \\`public.products\\`. The\n-- provider maps name/sku/price/cost/stock onto real columns and stashes\n-- productType/barcode/brand in \\`products.metadata\\` — but categoryId,\n-- measurementUnitId, supplierId and defaultLocationId were accepted by\n-- CreateProductInput and then silently discarded. Nothing persisted them.\n--\n-- WHY A SATELLITE AND NOT COLUMNS ON public.products.\n--\n-- 1. \\`products.category_id\\` already exists and already FKs \\`public.categories\\`.\n-- It CANNOT hold a plg_inventory_product_categories id — the same collision\n-- packages/shop/migrations/0009_products_canonical.sql documents for shop.\n-- The inventory category is a different taxonomy living in a different table.\n--\n-- 2. A spine column must not reference a plugin-prefixed table. \\`products\\` is\n-- shared by every plugin and by the archetype layer; uninstall inventory and\n-- a \\`products.measurement_unit_id\\` FK dangles. Every FK here points from the\n-- plugin's own table into whatever it likes, which is the direction that\n-- survives.\n--\n-- 3. \\`ARCHETYPE_COLUMNS.product\\` in packages/core/src/data/archetype.ts is a\n-- whitelist. splitFields() does not drop unknown keys, it routes them to an\n-- extension table — so adding a column to products without updating that set\n-- fails the write at runtime rather than at review.\n--\n-- plg_shop_products.product_id -> products.id is the shipped house pattern for\n-- exactly this; this follows it.\n--\n-- ON conversion_factor / purchase_unit_id. Artorius uses neither today\n-- (purchase_unit_id NULL on all 43 rows, conversion_factor 1.0 on all 43), and\n-- a plg_inventory_unit_conversions table would ship empty with no UI able to\n-- fill it. These two columns are the cheap hedge for the one case that does\n-- recur in a kitchen — buy in boxes, consume in grams — and cost two columns\n-- instead of a table and a screen.\n-- ============================================================================\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_details (\n product_id uuid PRIMARY KEY REFERENCES public.products(id) ON DELETE CASCADE,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n category_id uuid REFERENCES public.plg_inventory_product_categories(id) ON DELETE SET NULL,\n measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL,\n purchase_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL,\n conversion_factor numeric(14,4) NOT NULL DEFAULT 1,\n supplier_id uuid REFERENCES public.people(id) ON DELETE SET NULL,\n default_location_id uuid REFERENCES public.plg_inventory_stock_locations(id) ON DELETE SET NULL,\n purpose text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_product_details ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_product_details_tenant ON public.plg_inventory_product_details(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_product_details_category ON public.plg_inventory_product_details(category_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_product_details_supplier ON public.plg_inventory_product_details(supplier_id);\n\nCOMMENT ON COLUMN public.plg_inventory_product_details.purpose IS 'purchase | sale | both | menu. Unconstrained: the vocabulary is per-app labels, not a schema fact.';\nCOMMENT ON COLUMN public.plg_inventory_product_details.conversion_factor IS 'How many measurement_unit_id fit in one purchase_unit_id. 1 when the product is bought and consumed in the same unit.';\n\nNOTIFY pgrst, 'reload schema';\n`\n\nexport const MIGRATION_006_STOCK_POSITION_SLOTS = `-- ============================================================================\n-- 013_stock_position_slots.sql — make a stock position a slot, not a pile.\n--\n-- A row in plg_inventory_stock_positions is meant to be the on-hand quantity\n-- for one (product, location, batch, expiry) slot. Nothing enforced that. The\n-- provider's createMovement() does a read-modify-write through maybeSingle(),\n-- which means two rows for the same slot make maybeSingle() throw, and a\n-- concurrent write creates the duplicate in the first place.\n--\n-- This is not hypothetical: the Artorius source data carries 46 position rows\n-- across 37 distinct slots — the same defect, already realised, in the system\n-- we are migrating from.\n--\n-- The unique index is the half that matters. It turns the read-modify-write\n-- into an upsert with an inferrable conflict target.\n--\n-- WHY \\`NULLS NOT DISTINCT\\` AND NOT COALESCE EXPRESSIONS. batch_number and\n-- expiration_date are NULL on every row that does not track batches — which is\n-- most of them — and under default NULL semantics a plain unique index would\n-- consider each of those rows distinct and dedupe nothing at all. The portable\n-- alternative is an index over COALESCE expressions, but then ON CONFLICT can\n-- only be inferred by repeating those expressions verbatim, which supabase-js's\n-- \\`onConflict: 'col,col'\\` cannot express. Requires PostgreSQL 15+; Supabase has\n-- been 15+ since long before this plugin existed.\n--\n-- The fold below runs BEFORE the index because this file must also survive\n-- being applied to a pool that already accumulated duplicates.\n-- ============================================================================\n\nALTER TABLE public.plg_inventory_stock_positions\n ADD COLUMN IF NOT EXISTS measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL,\n ADD COLUMN IF NOT EXISTS unit_type text NOT NULL DEFAULT 'base',\n ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();\n\nCOMMENT ON COLUMN public.plg_inventory_stock_positions.unit_type IS 'base | purchase | content — which of the product''s units this quantity is counted in.';\n\n-- Fold pre-existing duplicate slots: quantities add, unit_cost becomes the\n-- weighted average of what it replaces. The survivor is picked by lowest id so\n-- that a re-run folds the same way; min(id::text) rather than min(id) because\n-- uuid has no ordering aggregate on every version we target.\nDO $$\nDECLARE folded integer;\nBEGIN\n WITH grouped AS (\n SELECT\n min(id::text)::uuid AS keep_id,\n tenant_id, product_id, stock_location_id, batch_number, expiration_date,\n sum(quantity) AS total_quantity,\n CASE WHEN sum(quantity) <> 0\n THEN sum(quantity * coalesce(unit_cost, 0)) / sum(quantity)\n ELSE max(unit_cost) END AS avg_unit_cost,\n count(*) AS n\n FROM public.plg_inventory_stock_positions\n GROUP BY tenant_id, product_id, stock_location_id, batch_number, expiration_date\n HAVING count(*) > 1\n ), updated AS (\n UPDATE public.plg_inventory_stock_positions p\n SET quantity = g.total_quantity,\n unit_cost = round(g.avg_unit_cost, 2),\n updated_at = now()\n FROM grouped g\n WHERE p.id = g.keep_id\n RETURNING p.id\n )\n DELETE FROM public.plg_inventory_stock_positions p\n USING grouped g\n WHERE p.tenant_id = g.tenant_id\n AND p.product_id = g.product_id\n AND p.stock_location_id IS NOT DISTINCT FROM g.stock_location_id\n AND p.batch_number IS NOT DISTINCT FROM g.batch_number\n AND p.expiration_date IS NOT DISTINCT FROM g.expiration_date\n AND p.id <> g.keep_id;\n\n GET DIAGNOSTICS folded = ROW_COUNT;\n IF folded > 0 THEN\n RAISE NOTICE 'plg_inventory_stock_positions: folded % duplicate row(s) into their slot', folded;\n END IF;\nEND $$;\n\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_inventory_stock_positions_slot\n ON public.plg_inventory_stock_positions\n (tenant_id, product_id, stock_location_id, batch_number, expiration_date)\n NULLS NOT DISTINCT;\n\nNOTIFY pgrst, 'reload schema';\n`\n\nexport const MIGRATION_007_RECIPE_GROUPS = `-- ============================================================================\n-- 014_recipe_groups.sql — a recipe's steps, not just its ingredient list.\n--\n-- plg_inventory_recipes + plg_inventory_recipe_ingredients model a flat bill of\n-- materials. A kitchen recipe is staged: \"massa\", \"recheio\", \"montagem\", each\n-- with its own ingredients, order and prep note. Metadata cannot express that —\n-- the group is a shared parent that several ingredient rows point at, and a\n-- jsonb blob per ingredient would duplicate the name and lose the ordering.\n--\n-- group_id is nullable on purpose: an ungrouped ingredient is the common case\n-- and stays valid. ON DELETE SET NULL so deleting a group flattens its\n-- ingredients back into the recipe rather than destroying them.\n-- ============================================================================\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_recipe_groups (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n recipe_id uuid NOT NULL REFERENCES public.plg_inventory_recipes(id) ON DELETE CASCADE,\n name text NOT NULL,\n preparation_notes text,\n display_order integer NOT NULL DEFAULT 0,\n estimated_minutes integer,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nALTER TABLE public.plg_inventory_recipe_groups ENABLE ROW LEVEL SECURITY;\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipe_groups_tenant ON public.plg_inventory_recipe_groups(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipe_groups_recipe ON public.plg_inventory_recipe_groups(recipe_id);\n\nALTER TABLE public.plg_inventory_recipe_ingredients\n ADD COLUMN IF NOT EXISTS group_id uuid REFERENCES public.plg_inventory_recipe_groups(id) ON DELETE SET NULL;\n\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_recipe_ingredients_group ON public.plg_inventory_recipe_ingredients(group_id);\n\nNOTIFY pgrst, 'reload schema';\n`\n\nexport const MIGRATION_008_RLS_POLICIES = `-- ============================================================================\n-- 015_rls_policies.sql — inventory stops borrowing the spine's sweep.\n--\n-- 001/002/003 ENABLE row-level security and create no policies. The policies\n-- that exist on live pools come from packages/db/migrations/002's auto-sweep,\n-- which discovers every public BASE TABLE carrying a tenant_id. That works, but\n-- only on the second pass: on a first-ever provision the spine step runs before\n-- the plugin step, so at sweep time these tables do not exist yet and come up\n-- RLS-enabled with NO policy — every insert denied. packages/db/test's replay\n-- pass exists partly to paper over exactly this.\n--\n-- plugin-financial solved it with its own 013_rls_policies.sql. This is the\n-- same file for inventory, and it also covers the two tables added by 005 and\n-- 007, which no sweep has ever seen.\n--\n-- NOTE, so it is not rediscovered as a bug: on pools that already ran the spine\n-- sweep, these tables will now carry TWO permissive policy families —\n-- \\`tenant_isolation_*\\` from the sweep and \\`<table>_*\\` from here. Permissive\n-- policies OR together and both quals are the identical canonical form, so the\n-- result is unchanged. It is noise in \\\\d output, not a hole.\n--\n-- Canonical RLS form: tenant_id IN (SELECT public.user_tenant_ids()).\n-- ============================================================================\n\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY[\n 'plg_inventory_product_categories','plg_inventory_stock_locations',\n 'plg_inventory_stock_movements','plg_inventory_stock_positions',\n 'plg_inventory_recipes','plg_inventory_recipe_ingredients',\n 'plg_inventory_measurement_units','plg_inventory_product_details',\n 'plg_inventory_recipe_groups'\n ])\n LOOP\n CONTINUE WHEN to_regclass('public.' || t) IS NULL;\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_select') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_select', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_insert') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_insert', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_update') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_update', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_delete') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_delete', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- plg_inventory_recipe_groups is tenant-scoped like the rest, so the loop above\n-- covers it. plg_inventory_product_details is keyed by product_id but carries\n-- tenant_id for exactly this reason.\n`\n\nexport const MIGRATION_009_AGENT_RPCS = `-- ============================================================================\n-- plugin-inventory 009: server-plane agent write RPC.\n--\n-- public.agent_inventory_upsert_recipe — the assistant BUILDS or EDITS a ficha\n-- técnica from any surface or channel (in-app FAB, WhatsApp, MCP). Same\n-- contract as every agent_* RPC (agenda 005, financial 009, forms 003):\n-- (p_tenant_id, p_actor_user_id, p_payload jsonb) → jsonb\n-- {ok:true, id, record:{...}} | {ok:false, denial:{...}} | {ok:false, error}\n--\n-- Ingredient NAMES are resolved to products.id HERE, so the model can say\n-- \"costela suína\" without holding an id. What it names and we cannot match is\n-- not silently dropped and not force-inserted (product_id is NOT NULL on the\n-- ingredient table): it lands in recipes.metadata->'unmatchedIngredients' and\n-- comes back in the result, so the screen can ask the user to pick or create\n-- it. That recovery loop is what made the legacy feature usable.\n--\n-- GRANT authenticated+service_role — NEVER anon (the broker calls with the pool\n-- service key and injects tenant/actor; in-browser the signed-in user calls it\n-- directly and spine RLS/actor guards bind them to their own tenant).\n-- ============================================================================\n\nALTER TABLE public.plg_inventory_recipes\n ADD COLUMN IF NOT EXISTS metadata jsonb;\n\nCOMMENT ON COLUMN public.plg_inventory_recipes.metadata IS 'What the assistant could not resolve: {unmatchedIngredients:[{name,quantity,notes}], productHint}.';\n\nCREATE OR REPLACE FUNCTION public.agent_inventory_upsert_recipe(\n p_tenant_id uuid,\n p_actor_user_id uuid,\n p_payload jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_recipe_id uuid;\n v_is_update boolean;\n v_name text;\n v_description text;\n v_instructions text;\n v_yield numeric;\n v_prep int;\n v_product_id uuid;\n v_product_hint text;\n v_item jsonb;\n v_iname text;\n v_qty numeric;\n v_pid uuid;\n v_order int := 0;\n v_resolved jsonb := '[]'::jsonb;\n v_unmatched jsonb := '[]'::jsonb;\n v_metadata jsonb;\n v_final_id uuid;\n v_final_name text;\nBEGIN\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_recipe_id := NULLIF(p_payload->>'recipe_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid recipe_id');\n END;\n v_is_update := v_recipe_id IS NOT NULL;\n v_name := btrim(p_payload->>'name');\n v_description := left(p_payload->>'description', 1000);\n v_instructions := left(p_payload->>'instructions', 8000);\n v_yield := COALESCE(NULLIF(p_payload->>'yield_quantity','')::numeric, 1);\n v_prep := NULLIF(p_payload->>'preparation_time_minutes','')::int;\n v_product_hint := btrim(COALESCE(p_payload->>'product_name',''));\n BEGIN\n v_product_id := NULLIF(p_payload->>'product_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n v_product_id := NULL;\n END;\n\n IF NOT v_is_update AND (v_name IS NULL OR v_name = '') THEN\n RETURN jsonb_build_object('ok', false, 'error', 'name is required to create a recipe');\n END IF;\n IF v_yield <= 0 THEN\n v_yield := 1;\n END IF;\n\n -- ── authorization: role → plan → recipes cap ─────────────────────────────\n SELECT count(*) INTO v_used FROM plg_inventory_recipes\n WHERE tenant_id = p_tenant_id AND is_active = true;\n v_denial := agent_guard(p_tenant_id, p_actor_user_id, 'inventory.recipes',\n CASE WHEN v_is_update THEN 'update' ELSE 'create' END,\n 'recipes', v_used, CASE WHEN v_is_update THEN 0 ELSE 1 END);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n IF v_is_update THEN\n PERFORM 1 FROM plg_inventory_recipes\n WHERE id = v_recipe_id AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown recipe for this tenant');\n END IF;\n END IF;\n\n -- ── produced product: id must be this tenant's, else resolve by name ──────\n IF v_product_id IS NOT NULL THEN\n PERFORM 1 FROM products WHERE id = v_product_id AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN v_product_id := NULL; END IF;\n END IF;\n IF v_product_id IS NULL AND v_product_hint <> '' THEN\n SELECT p.id INTO v_product_id FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND lower(btrim(p.name)) = lower(v_product_hint)\n ORDER BY p.is_active DESC LIMIT 1;\n IF v_product_id IS NULL THEN\n -- Containment rather than ILIKE: the name is user text and % / _ in it\n -- would be read as wildcards.\n SELECT p.id INTO v_product_id FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND position(lower(v_product_hint) in lower(p.name)) > 0\n ORDER BY length(p.name) LIMIT 1;\n END IF;\n END IF;\n\n -- ── ingredients: name → products.id, unresolved ones set aside ───────────\n FOR v_item IN SELECT value FROM jsonb_array_elements(COALESCE(p_payload->'ingredients','[]'::jsonb))\n LOOP\n v_iname := btrim(COALESCE(v_item->>'name', v_item->>'product_name', ''));\n v_qty := COALESCE(NULLIF(v_item->>'quantity','')::numeric, 0);\n BEGIN\n v_pid := NULLIF(v_item->>'product_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n v_pid := NULL;\n END;\n\n IF v_pid IS NOT NULL THEN\n PERFORM 1 FROM products WHERE id = v_pid AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN v_pid := NULL; END IF;\n END IF;\n\n IF v_pid IS NULL AND v_iname <> '' THEN\n SELECT p.id INTO v_pid FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND lower(btrim(p.name)) = lower(v_iname)\n ORDER BY p.is_active DESC LIMIT 1;\n IF v_pid IS NULL THEN\n SELECT p.id INTO v_pid FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND position(lower(v_iname) in lower(p.name)) > 0\n ORDER BY length(p.name) LIMIT 1;\n END IF;\n END IF;\n\n IF v_pid IS NULL OR v_qty <= 0 THEN\n v_unmatched := v_unmatched || jsonb_build_object(\n 'name', v_iname, 'quantity', v_qty, 'notes', NULLIF(v_item->>'notes',''));\n ELSE\n v_resolved := v_resolved || jsonb_build_object(\n 'product_id', v_pid, 'quantity', v_qty,\n 'notes', NULLIF(v_item->>'notes',''), 'display_order', v_order);\n v_order := v_order + 1;\n END IF;\n END LOOP;\n\n v_metadata := jsonb_strip_nulls(jsonb_build_object(\n 'unmatchedIngredients',\n CASE WHEN jsonb_array_length(v_unmatched) > 0 THEN v_unmatched ELSE NULL END,\n 'productHint',\n CASE WHEN v_product_id IS NULL AND v_product_hint <> '' THEN v_product_hint ELSE NULL END\n ));\n\n -- ── write + audit ────────────────────────────────────────────────────────\n IF v_is_update THEN\n UPDATE plg_inventory_recipes SET\n name = COALESCE(NULLIF(v_name,''), name),\n description = COALESCE(v_description, description),\n product_id = COALESCE(v_product_id, product_id),\n yield_quantity = COALESCE(NULLIF(NULLIF(p_payload->>'yield_quantity','')::numeric, 0), yield_quantity),\n preparation_time_minutes = COALESCE(v_prep, preparation_time_minutes),\n instructions = COALESCE(v_instructions, instructions),\n -- An edit that says nothing about ingredients must not erase the gaps the\n -- user still has to resolve.\n metadata = CASE WHEN p_payload ? 'ingredients' OR v_product_hint <> ''\n THEN v_metadata ELSE metadata END,\n updated_at = now()\n WHERE id = v_recipe_id AND tenant_id = p_tenant_id\n RETURNING id, name INTO v_final_id, v_final_name;\n ELSE\n INSERT INTO plg_inventory_recipes (\n tenant_id, name, description, product_id, yield_quantity,\n preparation_time_minutes, instructions, metadata\n ) VALUES (\n p_tenant_id, v_name, v_description, v_product_id, v_yield,\n v_prep, v_instructions, v_metadata\n )\n RETURNING id, name INTO v_final_id, v_final_name;\n END IF;\n\n -- \\`ingredients\\` REPLACES the list; omitting the key leaves the recipe's own.\n IF p_payload ? 'ingredients' THEN\n DELETE FROM plg_inventory_recipe_ingredients\n WHERE recipe_id = v_final_id AND tenant_id = p_tenant_id;\n INSERT INTO plg_inventory_recipe_ingredients (\n tenant_id, recipe_id, product_id, quantity, notes, display_order\n )\n SELECT p_tenant_id, v_final_id, (e->>'product_id')::uuid,\n (e->>'quantity')::numeric, NULLIF(e->>'notes',''), (e->>'display_order')::int\n FROM jsonb_array_elements(v_resolved) e;\n END IF;\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id,\n CASE WHEN v_is_update THEN 'agent.updateRecipe' ELSE 'agent.createRecipe' END,\n 'inventory_recipe', v_final_id::text,\n jsonb_build_object('payload', p_payload));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_final_id,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_final_id, 'resource', 'plg_inventory_recipes',\n 'archetype', 'inventory:recipe'),\n 'name', v_final_name,\n 'productId', v_product_id,\n 'ingredientCount', jsonb_array_length(v_resolved),\n 'unmatchedIngredients', v_unmatched,\n 'productHint', CASE WHEN v_product_id IS NULL THEN NULLIF(v_product_hint,'') ELSE NULL END\n )\n );\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.agent_inventory_upsert_recipe(uuid, uuid, jsonb) FROM public;\nREVOKE EXECUTE ON FUNCTION public.agent_inventory_upsert_recipe(uuid, uuid, jsonb) FROM anon;\nGRANT EXECUTE ON FUNCTION public.agent_inventory_upsert_recipe(uuid, uuid, jsonb)\n TO authenticated, service_role;\n\nNOTIFY pgrst, 'reload schema';\n`\n\nexport const MIGRATION_010_STOCK_COUNTS = `-- ============================================================================\n-- 017_stock_counts.sql — the physical count, as a session.\n--\n-- Until now the only correction this module offered was a per-product\n-- \\`adjustment\\` movement with a free-text reason. One product at a time, and no\n-- record of the count that motivated it: the number changed and nobody could\n-- say why, or against what. A dark kitchen closes its month against physical\n-- stock, so the count itself has to be a first-class record.\n--\n-- A session scopes to ONE stock location and optionally to one category, and\n-- lives through open → counting → closed (or cancelled).\n--\n-- DESIGN DECISIONS, and why:\n--\n-- 1. SNAPSHOT AT OPEN, NOT AT CLOSE. A count takes an hour, and the system\n-- total moves while it happens — a delivery arrives, a dish is produced.\n-- Comparing what was counted at 09:20 against what the system believes at\n-- 10:30 produces a variance that describes the clock, not the shelf. So\n-- \\`system_quantity\\` is written onto the item row when the session opens,\n-- inside inventory_open_count_session, in one consistent read.\n--\n-- 2. UNCOUNTED IS NOT ZERO. \\`counted_quantity\\` is NULLABLE, and NULL is the\n-- whole point: it means nobody looked. The close emits nothing for those\n-- lines. Treating them as zero would wipe the stock of every product the\n-- counter skipped — the single most destructive thing this feature could do.\n-- \"Counted zero\" is a real, different answer, and it is stored as 0.\n--\n-- 3. BLIND BY DEFAULT. \\`blind\\` hides the system quantity while counting, so\n-- the counter writes what is on the shelf instead of confirming what is on\n-- the screen. A count that shows you the answer first is a rubber stamp. It\n-- is a per-session flag because a targeted recount of a known discrepancy is\n-- a legitimate reason to turn it off.\n--\n-- 4. LOCATION IS REQUIRED. The close has to write a stock POSITION, and a\n-- position is (product, location, batch, expiry). A session without a\n-- location would have nowhere unambiguous to put the correction.\n--\n-- 5. THE COUNT IS AT PRODUCT × LOCATION, NOT PER BATCH. \\`system_quantity\\` sums\n-- every batch slot in the location, and the close applies the variance to\n-- the untracked (batch NULL) slot, leaving batch-tracked slots alone.\n-- Counting per batch would mean asking the counter to read lot codes off\n-- frozen packaging; deliberately out of scope.\n--\n-- 6. THE CLOSE IS ONE TRANSACTION AND IS IDEMPOTENT. It is a SECURITY DEFINER\n-- function so that the movement, the position and products.stock cannot end\n-- up half-written, and re-closing emits nothing: the session row is locked\n-- FOR UPDATE, a session already \\`closed\\` returns immediately, and each item\n-- remembers the movement it produced in \\`movement_id\\`, so a line that\n-- already adjusted can never adjust twice.\n--\n-- 7. THE ADJUSTMENT'S QUANTITY IS THE COUNTED (ABSOLUTE) FIGURE. The module's\n-- own vocabulary declares \\`adjustment\\` as effect \\`set\\` — the quantity is the\n-- new truth, not a delta. The variance is preserved on the item row and in\n-- the movement's metadata, and the position and products.stock move by the\n-- delta.\n--\n-- SECURITY: both functions are SECURITY DEFINER and therefore fence the tenant\n-- themselves — \\`tenant_id IN (SELECT public.user_tenant_ids())\\`, which resolves\n-- from auth.uid(). A service-role caller with no JWT is denied by that fence\n-- rather than being handed a cross-tenant write.\n--\n-- Canonical RLS form: tenant_id IN (SELECT public.user_tenant_ids()).\n-- Idempotent throughout.\n-- ============================================================================\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_count_sessions (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n reference text,\n status text NOT NULL DEFAULT 'open',\n stock_location_id uuid NOT NULL REFERENCES public.plg_inventory_stock_locations(id),\n category_id uuid REFERENCES public.plg_inventory_product_categories(id) ON DELETE SET NULL,\n blind boolean NOT NULL DEFAULT true,\n notes text,\n opened_at timestamptz NOT NULL DEFAULT now(),\n opened_by uuid,\n closed_at timestamptz,\n closed_by uuid,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nDO $$\nBEGIN\n IF NOT EXISTS (\n SELECT 1 FROM pg_constraint\n WHERE conname = 'plg_inventory_count_sessions_status_check'\n AND conrelid = 'public.plg_inventory_count_sessions'::regclass\n ) THEN\n ALTER TABLE public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_status_check\n CHECK (status IN ('open','counting','closed','cancelled'));\n END IF;\nEND $$;\n\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_count_sessions_tenant\n ON public.plg_inventory_count_sessions(tenant_id, opened_at DESC);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_count_sessions_status\n ON public.plg_inventory_count_sessions(tenant_id, status);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_count_items (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n session_id uuid NOT NULL REFERENCES public.plg_inventory_count_sessions(id) ON DELETE CASCADE,\n product_id uuid NOT NULL REFERENCES public.products(id),\n system_quantity numeric(14,4) NOT NULL DEFAULT 0,\n counted_quantity numeric(14,4),\n unit_cost numeric(14,2) NOT NULL DEFAULT 0,\n notes text,\n counted_at timestamptz,\n counted_by uuid,\n movement_id uuid REFERENCES public.plg_inventory_stock_movements(id) ON DELETE SET NULL,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCOMMENT ON COLUMN public.plg_inventory_count_items.system_quantity IS 'What the system believed when the session OPENED — never re-read at close.';\nCOMMENT ON COLUMN public.plg_inventory_count_items.counted_quantity IS 'NULL means nobody counted this line. It is not zero and never emits an adjustment.';\nCOMMENT ON COLUMN public.plg_inventory_count_items.movement_id IS 'The adjustment this line already emitted. Set exactly once — the per-line idempotency key of the close.';\n\nCREATE UNIQUE INDEX IF NOT EXISTS uq_plg_inventory_count_items_line\n ON public.plg_inventory_count_items(session_id, product_id);\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_count_items_tenant\n ON public.plg_inventory_count_items(tenant_id);\n\n-- ── RLS, same shape as 008 ──────────────────────────────────────────────────\nDO $$\nDECLARE t text;\nBEGIN\n FOR t IN SELECT unnest(ARRAY[\n 'plg_inventory_count_sessions','plg_inventory_count_items'\n ])\n LOOP\n CONTINUE WHEN to_regclass('public.' || t) IS NULL;\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_select') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_select', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_insert') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_insert', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_update') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_update', t);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_delete') THEN\n EXECUTE format('CREATE POLICY %I ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_delete', t);\n END IF;\n END LOOP;\nEND $$;\n\n-- ── open: create the session AND snapshot it, in one read ───────────────────\nCREATE OR REPLACE FUNCTION public.inventory_open_count_session(\n p_stock_location_id uuid,\n p_category_id uuid DEFAULT NULL,\n p_reference text DEFAULT NULL,\n p_blind boolean DEFAULT true,\n p_notes text DEFAULT NULL\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_tenant uuid;\n v_session_id uuid;\nBEGIN\n SELECT tenant_id INTO v_tenant\n FROM plg_inventory_stock_locations WHERE id = p_stock_location_id;\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory_open_count_session: unknown stock location %', p_stock_location_id;\n END IF;\n IF v_tenant NOT IN (SELECT public.user_tenant_ids()) THEN\n RAISE EXCEPTION 'inventory_open_count_session: not a member of this tenant';\n END IF;\n\n INSERT INTO plg_inventory_count_sessions (\n tenant_id, reference, status, stock_location_id, category_id, blind, notes, opened_by\n ) VALUES (\n v_tenant, NULLIF(btrim(COALESCE(p_reference, '')), ''), 'open',\n p_stock_location_id, p_category_id, COALESCE(p_blind, true),\n NULLIF(btrim(COALESCE(p_notes, '')), ''), auth.uid()\n )\n RETURNING id INTO v_session_id;\n\n -- Assets are patrimony, not stock, so they are never on a count sheet.\n INSERT INTO plg_inventory_count_items (\n tenant_id, session_id, product_id, system_quantity, unit_cost\n )\n SELECT\n v_tenant, v_session_id, p.id,\n COALESCE(pos.quantity, 0),\n COALESCE(pos.unit_cost, p.cost, 0)\n FROM products p\n LEFT JOIN plg_inventory_product_details d ON d.product_id = p.id\n LEFT JOIN LATERAL (\n SELECT sum(sp.quantity) AS quantity, max(sp.unit_cost) AS unit_cost\n FROM plg_inventory_stock_positions sp\n WHERE sp.tenant_id = v_tenant\n AND sp.product_id = p.id\n AND sp.stock_location_id = p_stock_location_id\n ) pos ON true\n WHERE p.tenant_id = v_tenant\n AND p.is_active = true\n AND COALESCE(p.metadata->>'productType', 'sale') <> 'asset'\n AND (p_category_id IS NULL OR d.category_id = p_category_id);\n\n RETURN v_session_id;\nEND;\n$$;\n\n-- ── close: one transaction, one adjustment per divergent counted line ───────\nCREATE OR REPLACE FUNCTION public.inventory_close_count_session(\n p_session_id uuid,\n p_reason text DEFAULT NULL\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER\nSET search_path = public\nAS $$\nDECLARE\n v_session plg_inventory_count_sessions%ROWTYPE;\n v_item plg_inventory_count_items%ROWTYPE;\n v_delta numeric;\n v_movement_id uuid;\n v_reason text;\n v_emitted int := 0;\nBEGIN\n -- The lock is what makes two simultaneous closes serialise instead of both\n -- reading \\`counting\\` and both emitting.\n SELECT * INTO v_session FROM plg_inventory_count_sessions\n WHERE id = p_session_id FOR UPDATE;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown count session');\n END IF;\n IF v_session.tenant_id NOT IN (SELECT public.user_tenant_ids()) THEN\n RAISE EXCEPTION 'inventory_close_count_session: not a member of this tenant';\n END IF;\n\n IF v_session.status = 'closed' THEN\n RETURN jsonb_build_object('ok', true, 'session_id', p_session_id,\n 'status', 'closed', 'already_closed', true, 'adjustments_created', 0);\n END IF;\n IF v_session.status = 'cancelled' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'this count was cancelled');\n END IF;\n\n v_reason := COALESCE(NULLIF(btrim(COALESCE(p_reason, '')), ''), 'Stock count');\n\n FOR v_item IN\n SELECT * FROM plg_inventory_count_items\n WHERE session_id = p_session_id\n AND counted_quantity IS NOT NULL\n AND counted_quantity <> system_quantity\n AND movement_id IS NULL\n ORDER BY id\n FOR UPDATE\n LOOP\n v_delta := v_item.counted_quantity - v_item.system_quantity;\n\n INSERT INTO plg_inventory_stock_movements (\n tenant_id, product_id, quantity, movement_type, unit_cost, total_cost,\n stock_location_id, reason, movement_date, user_id, metadata\n ) VALUES (\n v_session.tenant_id, v_item.product_id, v_item.counted_quantity, 'adjustment',\n v_item.unit_cost, v_item.unit_cost * v_item.counted_quantity,\n v_session.stock_location_id, v_reason, CURRENT_DATE, auth.uid(),\n jsonb_build_object(\n 'countSessionId', p_session_id,\n 'countItemId', v_item.id,\n 'systemQuantity', v_item.system_quantity,\n 'countedQuantity', v_item.counted_quantity,\n 'variance', v_delta\n )\n )\n RETURNING id INTO v_movement_id;\n\n UPDATE plg_inventory_count_items\n SET movement_id = v_movement_id, updated_at = now()\n WHERE id = v_item.id;\n\n -- The variance lands on the untracked slot; batch slots keep their lots.\n INSERT INTO plg_inventory_stock_positions (\n tenant_id, product_id, stock_location_id, quantity, unit_cost\n ) VALUES (\n v_session.tenant_id, v_item.product_id, v_session.stock_location_id,\n v_delta, v_item.unit_cost\n )\n ON CONFLICT (tenant_id, product_id, stock_location_id, batch_number, expiration_date)\n DO UPDATE SET\n quantity = plg_inventory_stock_positions.quantity + EXCLUDED.quantity,\n updated_at = now();\n\n UPDATE products SET stock = COALESCE(stock, 0) + v_delta, updated_at = now()\n WHERE id = v_item.product_id AND tenant_id = v_session.tenant_id;\n\n v_emitted := v_emitted + 1;\n END LOOP;\n\n UPDATE plg_inventory_count_sessions\n SET status = 'closed', closed_at = now(), closed_by = auth.uid(), updated_at = now()\n WHERE id = p_session_id;\n\n RETURN jsonb_build_object('ok', true, 'session_id', p_session_id,\n 'status', 'closed', 'already_closed', false, 'adjustments_created', v_emitted);\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.inventory_open_count_session(uuid, uuid, text, boolean, text) FROM public;\nREVOKE EXECUTE ON FUNCTION public.inventory_open_count_session(uuid, uuid, text, boolean, text) FROM anon;\nGRANT EXECUTE ON FUNCTION public.inventory_open_count_session(uuid, uuid, text, boolean, text)\n TO authenticated, service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_close_count_session(uuid, text) FROM public;\nREVOKE EXECUTE ON FUNCTION public.inventory_close_count_session(uuid, text) FROM anon;\nGRANT EXECUTE ON FUNCTION public.inventory_close_count_session(uuid, text)\n TO authenticated, service_role;\n\nNOTIFY pgrst, 'reload schema';\n`\n\nexport const MIGRATION_011_SCAFFOLD = `-- 011_scaffold.sql — the inventory tables under the ONE RLS template (043\n-- app.scaffold_table), in SHADOW mode (PRD 01 R6 / #135).\n--\n-- Shadow keeps the canonical tenant policies and ADDS the <t>_authz_* template\n-- policies; app.shadow_report() compares both per member; the inventory-base\n-- slice (or an operator, app.scaffold_set_mode) flips to 'enforce' on\n-- evidence — both calls are idempotent and converge. Guarded per table.\n--\n-- Stock locations become units in V2 (PRD 06); until that slice lands, a\n-- pre-existing unit_id that does not resolve is parked in\n-- app.legacy_unit_quarantine (055) so the composite FK can be added.\n--\n-- NOT scaffolded here: plg_inventory_recipe_ingredients — its \\`unit_id\\` is the\n-- MEASUREMENT unit of the ingredient (002), not a business unit; the template\n-- would read it as app.units and the FK/backfill would destroy the value. The\n-- inventory-base slice renames it (measurement_unit_id) and scaffolds after —\n-- until then it keeps its canonical tenant policies (the doctor scan reports it\n-- as legacy-rls).\nDO $$\nDECLARE\n t record;\n v_n integer;\nBEGIN\n IF to_regprocedure('app.scaffold_table(regclass, text, text, boolean, text)') IS NULL THEN\n RAISE NOTICE 'plugin-inventory 004: app.scaffold_table missing (spine < 043) — skipped';\n RETURN;\n END IF;\n FOR t IN SELECT * FROM (VALUES\n ('plg_inventory_product_categories', 'inventory.product_category'),\n ('plg_inventory_stock_locations', 'inventory.stock_location'),\n ('plg_inventory_stock_movements', 'inventory.stock_movement'),\n ('plg_inventory_stock_positions', 'inventory.stock_position'),\n ('plg_inventory_recipes', 'inventory.recipe'),\n ('plg_inventory_measurement_units', 'inventory.measurement_unit')\n ) AS v(table_name, resource_type)\n LOOP\n IF to_regclass('public.' || t.table_name) IS NULL THEN CONTINUE; END IF;\n IF to_regprocedure('app.quarantine_legacy_unit_ids(regclass)') IS NOT NULL THEN\n v_n := app.quarantine_legacy_unit_ids(('public.' || t.table_name)::regclass);\n IF v_n > 0 THEN RAISE NOTICE 'plugin-inventory 004: % legacy unit_id value(s) of % parked in app.legacy_unit_quarantine', v_n, t.table_name; END IF;\n END IF;\n PERFORM app.scaffold_table(('public.' || t.table_name)::regclass, t.resource_type, 'inventory', false, 'shadow');\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t.table_name);\n EXECUTE format('GRANT ALL ON public.%I TO service_role', t.table_name);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_012_INVENTORY_CORE_CONTRACT = `-- ============================================================================\n-- 012_inventory_core_contract.sql — the inventory base contract (PRD 06 / #143):\n-- locations per unit, positions, append-only movements, product settings,\n-- reservations and the idempotency ledger, all on the authz scaffold (043).\n--\n-- Evolved IN PLACE (no production tenant on these tables): the plg_inventory_*\n-- names of 001 stay, columns are added/renamed behind guards, legacy values are\n-- mapped, and every table is stamped by app.scaffold_table (enforce). Balances\n-- are never written by app code: positions are DERIVED from movements by the\n-- writer trigger of 007 and movements are written only by the RPCs of 008 —\n-- both tables are gated by a session flag the RPCs set (single writer).\n--\n-- products.stock / products.min_stock: the inventory plugin no longer reads or\n-- writes them (balances come from the views of 007; the minimum lives in\n-- plg_inventory_product_settings). The columns are NOT dropped: the shop's\n-- 0009 mirror trigger and backfill INSERT still write products.stock, and the\n-- core archetype allow-list routes \\`stock\\`/\\`min_stock\\` for host entity defs —\n-- dropping would break both silently. They become one-way MIRRORS maintained\n-- by 007 (documented as deprecated in docs/data/phase-0/06-inventory-base.md).\n--\n-- Idempotent and replay-safe: IF NOT EXISTS / guarded DO blocks throughout.\n-- ============================================================================\n\n-- ─────────────────────── stock locations (per unit) ────────────────────\n-- A location belongs to exactly one unit: that is what scopes stock by unit.\n-- Legacy rows without a unit are parked at the tenant's hq unit; if a tenant\n-- has no hq yet the NOT NULL is expressed as a NOT VALID check that a later\n-- replay validates once every row has a unit.\nDO $$\nDECLARE r record;\nBEGIN\n UPDATE public.plg_inventory_stock_locations l\n SET unit_id = u.id\n FROM app.units u\n WHERE l.unit_id IS NULL AND u.tenant_id = l.tenant_id AND u.kind = 'hq';\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_locations WHERE unit_id IS NULL) THEN\n ALTER TABLE public.plg_inventory_stock_locations ALTER COLUMN unit_id SET NOT NULL;\n -- the NOT VALID check of an earlier replay is redundant once the column is NOT NULL\n ALTER TABLE public.plg_inventory_stock_locations DROP CONSTRAINT IF EXISTS plg_inventory_stock_locations_unit_required;\n ELSIF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_locations_unit_required'\n AND conrelid = 'public.plg_inventory_stock_locations'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_unit_required CHECK (unit_id IS NOT NULL) NOT VALID;\n RAISE NOTICE 'plg_inventory_stock_locations: rows without a unit and no hq unit to park them — unit_id NOT NULL left as NOT VALID check';\n END IF;\nEND $$;\n\nALTER TABLE public.plg_inventory_stock_locations ADD COLUMN IF NOT EXISTS code text;\nALTER TABLE public.plg_inventory_stock_locations ADD COLUMN IF NOT EXISTS metadata jsonb NOT NULL DEFAULT '{}'::jsonb;\n\nSELECT app.scaffold_table('public.plg_inventory_stock_locations', 'inventory.stock_location', 'inventory', false, 'enforce');\n\n-- One name per unit (case-insensitive) — only when the pool has no duplicates yet.\nDO $$\nBEGIN\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_stock_locations\n GROUP BY tenant_id, unit_id, lower(name) HAVING count(*) > 1\n ) THEN\n CREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_stock_locations_unit_name_key\n ON public.plg_inventory_stock_locations (tenant_id, unit_id, lower(name));\n ELSE\n RAISE NOTICE 'plg_inventory_stock_locations: duplicate names within a unit — unique index skipped';\n END IF;\nEND $$;\n\n-- The unit of a location with history is frozen: movements carry the unit at the\n-- time they happened and are append-only, so re-parenting a location would leave\n-- its ledger under the old unit. Deactivate and create a new one instead.\nCREATE OR REPLACE FUNCTION app.inventory_locations_before_update()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF NEW.unit_id IS DISTINCT FROM OLD.unit_id\n AND EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = OLD.tenant_id\n AND (m.source_location_id = OLD.id OR m.destination_location_id = OLD.id)) THEN\n RAISE EXCEPTION 'inventory: a stock location with movements cannot change unit (deactivate it and create a new one)'\n USING ERRCODE = '55000';\n END IF;\n IF NEW.tenant_id IS DISTINCT FROM OLD.tenant_id THEN\n RAISE EXCEPTION 'inventory: a stock location cannot change tenant' USING ERRCODE = '55000';\n END IF;\n RETURN NEW;\nEND $$;\n-- (trigger created after the movements table below has its final columns)\n\n-- ─────────────────────── movements (append-only ledger) ────────────────\n-- Column evolution behind guards: movement_type → kind (values mapped),\n-- stock_location_id → source_location_id. document_number keeps main's name.\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements' AND column_name = 'movement_type')\n AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements' AND column_name = 'kind') THEN\n ALTER TABLE public.plg_inventory_stock_movements RENAME COLUMN movement_type TO kind;\n END IF;\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements' AND column_name = 'stock_location_id')\n AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements' AND column_name = 'source_location_id') THEN\n ALTER TABLE public.plg_inventory_stock_movements RENAME COLUMN stock_location_id TO source_location_id;\n END IF;\n -- \\`document_number\\` KEEPS main's name. The other two renames earn their churn\n -- (a transfer needs an origin and a destination; a \\`type\\` that is really a\n -- kind), this one was only taste — and taste is not worth a third compat\n -- mirror on a table the applied 004_stock_movement_view still selects.\nEND $$;\n\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS kind text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS source_location_id uuid REFERENCES public.plg_inventory_stock_locations(id);\n\n-- The three renamed columns come back as GENERATED mirrors, and they are not\n-- decoration. The renames above are semantic — a transfer has an origin AND a\n-- destination, and \\`movement_type\\` was a type that is really a kind — but\n-- \\`004_stock_movement_view\\` is an APPLIED file that selects the old names, and an\n-- applied file is never edited. Without these, the chain applies once and fails\n-- on replay: 004 runs again, the columns it needs are gone, and the run is red\n-- for renames that were right.\n--\n-- Generated and stored, so they cannot drift from what they mirror and cannot be\n-- written to by accident. They go at the cut-over, with the rest of the\n-- compatibility surface.\nDO $$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM (VALUES\n ('stock_location_id', 'source_location_id', 'uuid'),\n ('movement_type', 'kind', 'text')\n ) AS v(old_name, new_name, typ) LOOP\n CONTINUE WHEN EXISTS (SELECT 1 FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements'\n AND column_name = r.old_name);\n CONTINUE WHEN NOT EXISTS (SELECT 1 FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements'\n AND column_name = r.new_name);\n EXECUTE format('ALTER TABLE public.plg_inventory_stock_movements ADD COLUMN %I %s GENERATED ALWAYS AS (%I) STORED',\n r.old_name, r.typ, r.new_name);\n EXECUTE format('COMMENT ON COLUMN public.plg_inventory_stock_movements.%I IS %L',\n r.old_name, format('DEPRECATED compat mirror of %s, kept so the applied 004_stock_movement_view stays replay-safe. Dropped at the cut-over.', r.new_name));\n END LOOP;\nEND $$;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS destination_location_id uuid REFERENCES public.plg_inventory_stock_locations(id);\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS document_type text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS document_number text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS reverses_movement_id uuid REFERENCES public.plg_inventory_stock_movements(id);\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS idempotency_key text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS line_no integer NOT NULL DEFAULT 1;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS operation_id uuid;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS source_item_type text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS source_item_id uuid;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id);\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS batch_number text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS expiration_date date;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS reason text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS notes text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS user_id uuid;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS metadata jsonb DEFAULT '{}'::jsonb;\n-- fractions of a cent per mL are real: widen the money columns (guarded on the\n-- current typmod — a same-type ALTER would still trip over the views of 013 on replay)\n--\n-- A dependent view makes ALTER TYPE fail outright, and \\`main\\` grew one this file\n-- never knew about (\\`v_stock_movements\\`, from inventory 004). Rather than name\n-- it — the next one would fail the same way — the dependents are captured from\n-- the catalog, dropped, and rebuilt from their own definitions afterwards.\nCREATE TEMP TABLE IF NOT EXISTS _dep_views (nspname text, relname text, def text, owner text);\nDO $$\nDECLARE r record;\nBEGIN\n FOR r IN\n SELECT DISTINCT n.nspname, c.relname, pg_get_viewdef(c.oid, true) AS def, pg_get_userbyid(c.relowner) AS owner\n FROM pg_depend d\n JOIN pg_rewrite rw ON rw.oid = d.objid\n JOIN pg_class c ON c.oid = rw.ev_class AND c.relkind IN ('v', 'm')\n JOIN pg_namespace n ON n.oid = c.relnamespace\n WHERE d.refobjid = 'public.plg_inventory_stock_movements'::regclass\n AND d.refobjsubid > 0\n LOOP\n INSERT INTO _dep_views VALUES (r.nspname, r.relname, r.def, r.owner);\n EXECUTE format('DROP VIEW IF EXISTS %I.%I CASCADE', r.nspname, r.relname);\n RAISE NOTICE '012: dependent view %.% dropped for the column widening, rebuilt below', r.nspname, r.relname;\n END LOOP;\nEND $$;\n\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements'\n AND column_name = 'unit_cost' AND (numeric_precision, numeric_scale) IS DISTINCT FROM (16, 4)) THEN\n ALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN unit_cost TYPE numeric(16,4);\n END IF;\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements'\n AND column_name = 'total_cost' AND (numeric_precision, numeric_scale) IS DISTINCT FROM (16, 4)) THEN\n ALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN total_cost TYPE numeric(16,4);\n END IF;\nEND $$;\nALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN unit_cost SET DEFAULT 0;\nALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN total_cost SET DEFAULT 0;\nUPDATE public.plg_inventory_stock_movements SET unit_cost = 0 WHERE unit_cost IS NULL;\nUPDATE public.plg_inventory_stock_movements SET total_cost = 0 WHERE total_cost IS NULL;\nALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN unit_cost SET NOT NULL;\nALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN total_cost SET NOT NULL;\n\n-- …and the dependents come back exactly as they were.\nDO $$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM _dep_views LOOP\n EXECUTE format('CREATE OR REPLACE VIEW %I.%I AS %s', r.nspname, r.relname, r.def);\n EXECUTE format('ALTER VIEW %I.%I OWNER TO %I', r.nspname, r.relname, r.owner);\n -- …and it comes back INVOKER. main's 043_view_invoker swept the core views\n -- and could not reach a plugin's, so v_stock_movements was still answering\n -- with the owner's rights over a tenant_id table — the same hole, one tree\n -- further out. 900_verification/001 N16 is what caught it.\n EXECUTE format('ALTER VIEW %I.%I SET (security_invoker = true)', r.nspname, r.relname);\n END LOOP;\n DELETE FROM _dep_views;\nEND $$;\n\n-- Legacy kind values (SDK enum and V1 labels) converge onto the five kinds.\n-- Quantity is SIGNED = the effect on the position at (product, source_location,\n-- batch, expiry); the destination (transfer / reversed transfer) gets −quantity.\nUPDATE public.plg_inventory_stock_movements SET kind = CASE lower(coalesce(kind, ''))\n WHEN 'in' THEN 'in' WHEN 'entry' THEN 'in' WHEN 'entrada' THEN 'in' WHEN 'receipt' THEN 'in' WHEN 'purchase' THEN 'in'\n WHEN 'out' THEN 'out' WHEN 'exit' THEN 'out' WHEN 'saida' THEN 'out' WHEN 'saída' THEN 'out' WHEN 'loss' THEN 'out' WHEN 'perda' THEN 'out' WHEN 'sale' THEN 'out' WHEN 'consumption' THEN 'out'\n WHEN 'transfer' THEN 'transfer' WHEN 'transferencia' THEN 'transfer' WHEN 'transferência' THEN 'transfer'\n WHEN 'reverse' THEN 'reverse' WHEN 'estorno' THEN 'reverse' WHEN 'reversal' THEN 'reverse'\n ELSE 'adjust' END,\n quantity = CASE\n WHEN lower(coalesce(kind, '')) IN ('out', 'exit', 'saida', 'saída', 'loss', 'perda', 'sale', 'consumption', 'transfer', 'transferencia', 'transferência') AND quantity > 0 THEN -quantity\n ELSE quantity END\n WHERE kind IS NULL OR kind NOT IN ('in', 'out', 'transfer', 'adjust', 'reverse');\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_kind_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_kind_check CHECK (kind IN ('in', 'out', 'transfer', 'adjust', 'reverse'));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_quantity_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_quantity_check CHECK (quantity <> 0);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_sign_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_sign_check CHECK (\n (kind = 'in' AND quantity > 0) OR (kind = 'out' AND quantity < 0) OR (kind = 'transfer' AND quantity < 0)\n OR kind IN ('adjust', 'reverse'));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_transfer_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_transfer_check CHECK (\n (kind = 'transfer' AND destination_location_id IS NOT NULL AND destination_location_id <> source_location_id)\n OR (kind IN ('in', 'out', 'adjust') AND destination_location_id IS NULL)\n OR kind = 'reverse');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_reverse_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_reverse_check CHECK (\n (kind = 'reverse') = (reverses_movement_id IS NOT NULL));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_cost_check' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_cost_check CHECK (unit_cost >= 0 AND total_cost >= 0);\n END IF;\nEND $$;\n\n-- a movement without a source location has no position to move.\n--\n-- WHY THIS IS AN INSERT RULE AND NOT A \\`NOT VALID\\` CHECK. It was one, and the\n-- shape does not hold: NOT VALID skips the rows already there at ADD time, but a\n-- CHECK is re-evaluated on every UPDATE of a row, so the legacy rows it spared\n-- become frozen — they can never be written again for any reason. That collides\n-- with this same chain two files later, where 018 has to fill \\`unit_id\\` on\n-- exactly those rows, and resto's pool proved it: 51 movements from before\n-- locations were required, none of them updatable.\n--\n-- \"Required from here on\" is a rule about INSERTs, so it is enforced where it\n-- belongs. New movements must name a source; the ones that predate the rule stay\n-- readable, stay updatable for backfills, and are never silently corrected.\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements WHERE source_location_id IS NULL) THEN\n ALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN source_location_id SET NOT NULL;\n END IF;\n -- The old shape is retired wherever it landed, including on a pool that took\n -- an earlier cut of this file.\n ALTER TABLE public.plg_inventory_stock_movements\n DROP CONSTRAINT IF EXISTS plg_inventory_stock_movements_source_required;\nEND $$;\n\nCREATE OR REPLACE FUNCTION app.inventory_movement_source_required()\nRETURNS trigger LANGUAGE plpgsql AS $$\nBEGIN\n IF NEW.source_location_id IS NULL THEN\n RAISE EXCEPTION 'inventory: a stock movement must name the location it moves from'\n USING ERRCODE = '23514';\n END IF;\n RETURN NEW;\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_source_required ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_source_required\n BEFORE INSERT ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_movement_source_required();\n\nSELECT app.scaffold_table('public.plg_inventory_stock_movements', 'inventory.stock_movement', 'inventory', false, 'enforce');\n\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_source_idx ON public.plg_inventory_stock_movements (tenant_id, source_location_id, product_id);\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_dest_idx ON public.plg_inventory_stock_movements (tenant_id, destination_location_id, product_id) WHERE destination_location_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_source_item_idx ON public.plg_inventory_stock_movements (tenant_id, source_item_type, source_item_id) WHERE source_item_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_created_idx ON public.plg_inventory_stock_movements (tenant_id, created_at DESC);\n-- one key + line per tenant: the ledger cannot hold the same line of the same\n-- operation twice (the operations table below is the replay authority)\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_stock_movements_idem_key\n ON public.plg_inventory_stock_movements (tenant_id, idempotency_key, line_no) WHERE idempotency_key IS NOT NULL;\n-- a movement is reversed at most once\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_stock_movements_reverses_key\n ON public.plg_inventory_stock_movements (reverses_movement_id) WHERE reverses_movement_id IS NOT NULL;\n\n-- Append-only: a correction is a new row (kind = 'reverse'), never an edit.\n-- Append-only means THE FACTS OF A MOVEMENT NEVER CHANGE: quantity, product,\n-- date, cost, location. It does not mean the row can never be touched again, and\n-- the difference decides whether a pool with years of stock behind it can adopt\n-- a scoping column that did not exist when those rows were written.\n--\n-- DELETE is always refused. UPDATE is refused unless it is exactly one thing: a\n-- scope column going from NULL to a value with every other column identical.\n-- That is a backfill, not a rewrite — 018 needs it, and nothing else gets in:\n-- moving a unit that was already set is still a reversal's job.\nCREATE OR REPLACE FUNCTION app.inventory_movements_append_only()\nRETURNS trigger LANGUAGE plpgsql AS $$\nDECLARE\n v_old jsonb;\n v_new jsonb;\n k text;\nBEGIN\n IF TG_OP = 'UPDATE' THEN\n v_old := to_jsonb(OLD);\n v_new := to_jsonb(NEW);\n FOREACH k IN ARRAY ARRAY['unit_id', 'owner_id', 'updated_at'] LOOP\n v_old := v_old - k;\n v_new := v_new - k;\n END LOOP;\n -- GENERATED columns read NULL in NEW inside a BEFORE trigger: Postgres\n -- computes them after these run. This table has two — the compat mirrors\n -- 107 left behind for stock_location_id and movement_type — so comparing\n -- them would report a change on every row and refuse every backfill.\n -- They are derived from the columns already being compared anyway.\n FOR k IN\n SELECT a.attname FROM pg_attribute a\n WHERE a.attrelid = TG_RELID AND a.attnum > 0\n AND NOT a.attisdropped AND a.attgenerated <> ''\n LOOP\n v_old := v_old - k;\n v_new := v_new - k;\n END LOOP;\n IF v_old = v_new\n AND (OLD.unit_id IS NULL OR NEW.unit_id IS NOT DISTINCT FROM OLD.unit_id)\n AND (OLD.owner_id IS NULL OR NEW.owner_id IS NOT DISTINCT FROM OLD.owner_id) THEN\n RETURN NEW;\n END IF;\n END IF;\n RAISE EXCEPTION 'inventory: stock movements are append-only (write a reversal instead)' USING ERRCODE = '55000';\nEND $$;\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_append_only ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_append_only\n BEFORE UPDATE OR DELETE ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_append_only();\n\nDROP TRIGGER IF EXISTS plg_inventory_stock_locations_before_update ON public.plg_inventory_stock_locations;\nCREATE TRIGGER plg_inventory_stock_locations_before_update\n BEFORE UPDATE ON public.plg_inventory_stock_locations\n FOR EACH ROW EXECUTE FUNCTION app.inventory_locations_before_update();\n\n-- ─────────────────────── positions (derived balances) ──────────────────\nALTER TABLE public.plg_inventory_stock_positions ADD COLUMN IF NOT EXISTS measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id);\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_positions'\n AND column_name = 'unit_cost' AND (numeric_precision, numeric_scale) IS DISTINCT FROM (16, 4)) THEN\n ALTER TABLE public.plg_inventory_stock_positions ALTER COLUMN unit_cost TYPE numeric(16,4);\n END IF;\nEND $$;\nALTER TABLE public.plg_inventory_stock_positions ALTER COLUMN unit_cost SET DEFAULT 0;\nUPDATE public.plg_inventory_stock_positions SET unit_cost = 0 WHERE unit_cost IS NULL;\nALTER TABLE public.plg_inventory_stock_positions ALTER COLUMN unit_cost SET NOT NULL;\n\n-- legacy positions without a location: park them at the tenant's oldest location\nUPDATE public.plg_inventory_stock_positions p\n SET stock_location_id = (SELECT l.id FROM public.plg_inventory_stock_locations l\n WHERE l.tenant_id = p.tenant_id ORDER BY l.created_at, l.id LIMIT 1)\n WHERE p.stock_location_id IS NULL;\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_positions WHERE stock_location_id IS NULL) THEN\n ALTER TABLE public.plg_inventory_stock_positions ALTER COLUMN stock_location_id SET NOT NULL;\n ALTER TABLE public.plg_inventory_stock_positions DROP CONSTRAINT IF EXISTS plg_inventory_stock_positions_location_required;\n ELSIF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_positions_location_required' AND conrelid = 'public.plg_inventory_stock_positions'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_location_required CHECK (stock_location_id IS NOT NULL) NOT VALID;\n RAISE NOTICE 'plg_inventory_stock_positions: legacy rows without a location and no location to park them — NOT NULL left as NOT VALID check';\n END IF;\nEND $$;\n\n-- merge legacy duplicates of one position identity (sum, weighted cost) so the\n-- unique index below can exist\nDO $$\nDECLARE d record;\nBEGIN\n IF EXISTS (SELECT 1 FROM public.plg_inventory_stock_positions\n GROUP BY tenant_id, product_id, stock_location_id, coalesce(batch_number, ''), coalesce(expiration_date, 'infinity'::date)\n HAVING count(*) > 1) THEN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n FOR d IN\n SELECT tenant_id, product_id, stock_location_id, coalesce(batch_number, '') AS b, coalesce(expiration_date, 'infinity'::date) AS e,\n sum(quantity) AS qty,\n CASE WHEN sum(quantity) <> 0 THEN sum(quantity * unit_cost) / sum(quantity) ELSE max(unit_cost) END AS cost,\n (array_agg(id ORDER BY created_at, id))[1] AS keep_id\n FROM public.plg_inventory_stock_positions\n GROUP BY 1, 2, 3, 4, 5 HAVING count(*) > 1\n LOOP\n UPDATE public.plg_inventory_stock_positions SET quantity = d.qty, unit_cost = coalesce(d.cost, 0) WHERE id = d.keep_id;\n DELETE FROM public.plg_inventory_stock_positions\n WHERE tenant_id = d.tenant_id AND product_id = d.product_id AND stock_location_id = d.stock_location_id\n AND coalesce(batch_number, '') = d.b AND coalesce(expiration_date, 'infinity'::date) = d.e AND id <> d.keep_id;\n END LOOP;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n END IF;\nEND $$;\n\nSELECT app.scaffold_table('public.plg_inventory_stock_positions', 'inventory.stock_position', 'inventory', false, 'enforce');\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_stock_positions_identity_key\n ON public.plg_inventory_stock_positions (tenant_id, product_id, stock_location_id, coalesce(batch_number, ''), coalesce(expiration_date, 'infinity'::date));\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_positions_location_idx ON public.plg_inventory_stock_positions (tenant_id, stock_location_id, product_id);\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_positions_expiry_idx ON public.plg_inventory_stock_positions (tenant_id, expiration_date) WHERE expiration_date IS NOT NULL;\n\n-- positions.unit_id mirrors the location's unit — that is what the RLS template scopes on\nUPDATE public.plg_inventory_stock_positions p\n SET unit_id = l.unit_id\n FROM public.plg_inventory_stock_locations l\n WHERE l.id = p.stock_location_id AND p.unit_id IS DISTINCT FROM l.unit_id;\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_positions_quantity_check' AND conrelid = 'public.plg_inventory_stock_positions'::regclass) THEN\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_positions WHERE quantity < 0) THEN\n ALTER TABLE public.plg_inventory_stock_positions ADD CONSTRAINT plg_inventory_stock_positions_quantity_check CHECK (quantity >= 0);\n ELSE\n ALTER TABLE public.plg_inventory_stock_positions ADD CONSTRAINT plg_inventory_stock_positions_quantity_check CHECK (quantity >= 0) NOT VALID;\n RAISE NOTICE 'plg_inventory_stock_positions: negative legacy balances — quantity >= 0 left as NOT VALID check';\n END IF;\n END IF;\nEND $$;\n\n-- ─────────────────────── product settings (min quantity) ───────────────\n-- The replacement for products.min_stock: per product, tenant-wide (unit_id\n-- NULL) or per unit. Also carries the product's stock unit of measure and its\n-- default location.\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_settings (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n product_id uuid NOT NULL REFERENCES public.products(id) ON DELETE CASCADE,\n min_quantity numeric(16,4) NOT NULL DEFAULT 0 CHECK (min_quantity >= 0),\n max_quantity numeric(16,4) CHECK (max_quantity IS NULL OR max_quantity >= 0),\n measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id),\n default_location_id uuid REFERENCES public.plg_inventory_stock_locations(id) ON DELETE SET NULL,\n track_batches boolean NOT NULL DEFAULT false,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nSELECT app.scaffold_table('public.plg_inventory_product_settings', 'inventory.product_settings', 'inventory', false, 'enforce');\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_product_settings_product_unit_key\n ON public.plg_inventory_product_settings (tenant_id, product_id, coalesce(unit_id, '00000000-0000-0000-0000-000000000000'::uuid));\n\n-- ─────────────────────── reservations (consumption hooks) ──────────────\n-- reserve → confirm turns into exactly one 'out' movement; reverse releases or\n-- writes the reversal. Keyed by the source item (the executed service line, the\n-- order item) through idempotency_key.\nCREATE TABLE IF NOT EXISTS public.plg_inventory_reservations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n idempotency_key text NOT NULL,\n line_no integer NOT NULL DEFAULT 1,\n source_type text NOT NULL,\n source_id uuid NOT NULL,\n product_id uuid NOT NULL REFERENCES public.products(id),\n stock_location_id uuid NOT NULL REFERENCES public.plg_inventory_stock_locations(id),\n batch_number text,\n expiration_date date,\n quantity numeric(16,4) NOT NULL CHECK (quantity > 0),\n measurement_unit_id uuid REFERENCES public.plg_inventory_measurement_units(id),\n status text NOT NULL DEFAULT 'reserved' CHECK (status IN ('reserved', 'confirmed', 'reversed')),\n movement_id uuid REFERENCES public.plg_inventory_stock_movements(id),\n reversal_movement_id uuid REFERENCES public.plg_inventory_stock_movements(id),\n reason text,\n confirmed_at timestamptz,\n confirmed_by uuid,\n reversed_at timestamptz,\n reversed_by 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);\nSELECT app.scaffold_table('public.plg_inventory_reservations', 'inventory.reservation', 'inventory', false, 'enforce');\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_reservations_key_line\n ON public.plg_inventory_reservations (tenant_id, idempotency_key, line_no);\nCREATE INDEX IF NOT EXISTS plg_inventory_reservations_source_idx\n ON public.plg_inventory_reservations (tenant_id, source_type, source_id);\nCREATE INDEX IF NOT EXISTS plg_inventory_reservations_open_idx\n ON public.plg_inventory_reservations (tenant_id, product_id, stock_location_id) WHERE status = 'reserved';\n\n-- ─────────────────────── operations (idempotency ledger) ───────────────\n-- One row per RPC call and key: replaying the same key returns the stored\n-- result and has no second effect. The unique index is what serializes two\n-- concurrent calls with the same key (the second waits, then reads the result).\nCREATE TABLE IF NOT EXISTS public.plg_inventory_operations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n kind text NOT NULL CHECK (kind IN ('receive', 'transfer', 'adjust', 'reserve', 'confirm', 'reverse')),\n idempotency_key text NOT NULL,\n status text NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'done')),\n actor_id uuid,\n request jsonb NOT NULL DEFAULT '{}'::jsonb,\n result jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nSELECT app.scaffold_table('public.plg_inventory_operations', 'inventory.operation', 'inventory', false, 'enforce');\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_operations_key\n ON public.plg_inventory_operations (tenant_id, kind, idempotency_key);\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_stock_movements_operation_fk' AND conrelid = 'public.plg_inventory_stock_movements'::regclass) THEN\n ALTER TABLE public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_operation_fk FOREIGN KEY (operation_id) REFERENCES public.plg_inventory_operations(id);\n END IF;\nEND $$;\n\n-- ─────────────────────── the single-writer gate ────────────────────────\n-- Positions are derived; movements are the ledger. Both are written only from\n-- inside the RPCs / the writer trigger, which set fayz.inventory_internal for the\n-- statement. Any other write path — however privileged — is refused with a\n-- message that says where to go instead.\nCREATE OR REPLACE FUNCTION app.inventory_internal_only()\nRETURNS trigger LANGUAGE plpgsql AS $$\nBEGIN\n IF coalesce(current_setting('fayz.inventory_internal', true), 'off') <> 'on' THEN\n RAISE EXCEPTION 'inventory: % is written only through the inventory RPCs (inventory_receive / _transfer / _adjust / _reserve / _confirm / _reverse)', TG_TABLE_NAME\n USING ERRCODE = '55000';\n END IF;\n IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;\n RETURN NEW;\nEND $$;\nDROP TRIGGER IF EXISTS plg_inventory_stock_positions_internal_only ON public.plg_inventory_stock_positions;\nCREATE TRIGGER plg_inventory_stock_positions_internal_only\n BEFORE INSERT OR UPDATE OR DELETE ON public.plg_inventory_stock_positions\n FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_internal_only ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_internal_only\n BEFORE INSERT ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\nDROP TRIGGER IF EXISTS plg_inventory_reservations_internal_only ON public.plg_inventory_reservations;\nCREATE TRIGGER plg_inventory_reservations_internal_only\n BEFORE INSERT OR UPDATE OR DELETE ON public.plg_inventory_reservations\n FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\nDROP TRIGGER IF EXISTS plg_inventory_operations_internal_only ON public.plg_inventory_operations;\nCREATE TRIGGER plg_inventory_operations_internal_only\n BEFORE INSERT OR UPDATE OR DELETE ON public.plg_inventory_operations\n FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\n\n-- ─────────────────────── grants ────────────────────────────────────────\n-- Reads for authenticated (RLS narrows); writes on the ledger tables revoked —\n-- the spine's blanket GRANT ALL (008) is re-issued on replay, so this file\n-- converges by revoking again after it.\nREVOKE ALL ON public.plg_inventory_stock_locations, public.plg_inventory_stock_positions, public.plg_inventory_stock_movements,\n public.plg_inventory_product_settings, public.plg_inventory_reservations, public.plg_inventory_operations FROM authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_inventory_stock_locations TO authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_inventory_product_settings TO authenticated;\nGRANT SELECT ON public.plg_inventory_stock_positions, public.plg_inventory_stock_movements,\n public.plg_inventory_reservations, public.plg_inventory_operations TO authenticated;\nGRANT ALL ON public.plg_inventory_stock_locations, public.plg_inventory_stock_positions, public.plg_inventory_stock_movements,\n public.plg_inventory_product_settings, public.plg_inventory_reservations, public.plg_inventory_operations TO service_role;\nREVOKE ALL ON public.plg_inventory_stock_locations, public.plg_inventory_stock_positions, public.plg_inventory_stock_movements,\n public.plg_inventory_product_settings, public.plg_inventory_reservations, public.plg_inventory_operations FROM anon;\n\nCOMMENT ON TABLE public.plg_inventory_stock_movements IS\n 'Append-only stock ledger (PRD 06). quantity is signed: the effect on the position at (product, source_location, batch, expiry); a transfer or reversed transfer applies -quantity at destination_location. Written only by the inventory_* RPCs.';\nCOMMENT ON TABLE public.plg_inventory_stock_positions IS\n 'Derived balances per (product, location, batch, expiry). Maintained by the movements writer trigger; never written by app code. Read through v_inventory_balances / v_inventory_product_totals.';\nCOMMENT ON TABLE public.plg_inventory_reservations IS\n 'Consumption hooks: inventory_reserve → inventory_confirm (one out movement, exactly once) → inventory_reverse. Keyed by the source item through idempotency_key.';\nCOMMENT ON TABLE public.plg_inventory_operations IS\n 'Idempotency ledger of the inventory RPCs: (tenant, kind, idempotency_key) → stored result. A replay returns the stored result and has no second effect.';\nCOMMENT ON TABLE public.plg_inventory_product_settings IS\n 'Per-product inventory settings (min/max quantity, stock unit, default location), tenant-wide (unit_id NULL) or per unit. Replaces products.min_stock.';\n`\n\nexport const MIGRATION_013_INVENTORY_UNITS = `-- ============================================================================\n-- 013_inventory_units.sql — measurement units and conversions in the inventory\n-- core (PRD 06 R2 / #143). \"bottle ↔ mL is a conversion, not a hack\".\n--\n-- plg_inventory_measurement_units (003) gains code / kind / is_base and the\n-- scaffold; plg_inventory_unit_conversions holds (from, to, factor), tenant-wide\n-- or per product (a 250 mL bottle of product X: bottle → mL × 250);\n-- public.inventory_convert() resolves a quantity between two units. The six\n-- standard units (un, cx, kg, g, L, mL) are seeded per tenant in SQL — for\n-- every existing tenant here, for every new tenant by trigger — replacing the\n-- TS-only seed (the TS seedData stays for mock mode).\n-- ============================================================================\n\nALTER TABLE public.plg_inventory_measurement_units ADD COLUMN IF NOT EXISTS code text;\nALTER TABLE public.plg_inventory_measurement_units ADD COLUMN IF NOT EXISTS kind text NOT NULL DEFAULT 'unit';\nALTER TABLE public.plg_inventory_measurement_units ADD COLUMN IF NOT EXISTS is_base boolean NOT NULL DEFAULT false;\nALTER TABLE public.plg_inventory_measurement_units ADD COLUMN IF NOT EXISTS metadata jsonb NOT NULL DEFAULT '{}'::jsonb;\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_measurement_units_kind_check' AND conrelid = 'public.plg_inventory_measurement_units'::regclass) THEN\n ALTER TABLE public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_kind_check CHECK (kind IN ('unit', 'mass', 'volume', 'length'));\n END IF;\nEND $$;\n-- legacy rows: derive a code from the abbreviation where none was set\nUPDATE public.plg_inventory_measurement_units SET code = lower(abbreviation) WHERE code IS NULL AND abbreviation IS NOT NULL;\nUPDATE public.plg_inventory_measurement_units SET kind = CASE lower(code)\n WHEN 'kg' THEN 'mass' WHEN 'g' THEN 'mass' WHEN 'mg' THEN 'mass'\n WHEN 'l' THEN 'volume' WHEN 'ml' THEN 'volume'\n WHEN 'm' THEN 'length' WHEN 'cm' THEN 'length' WHEN 'mm' THEN 'length'\n ELSE kind END\n WHERE kind = 'unit' AND lower(code) IN ('kg', 'g', 'mg', 'l', 'ml', 'm', 'cm', 'mm');\n\nSELECT app.scaffold_table('public.plg_inventory_measurement_units', 'inventory.measurement_unit', 'inventory', false, 'enforce');\n\nDO $$\nBEGIN\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_measurement_units WHERE code IS NOT NULL\n GROUP BY tenant_id, lower(code) HAVING count(*) > 1\n ) THEN\n CREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_measurement_units_code_key\n ON public.plg_inventory_measurement_units (tenant_id, lower(code)) WHERE code IS NOT NULL;\n ELSE\n RAISE NOTICE 'plg_inventory_measurement_units: duplicate codes within a tenant — unique index skipped';\n END IF;\nEND $$;\n-- one base unit per kind per tenant\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_measurement_units_base_key\n ON public.plg_inventory_measurement_units (tenant_id, kind) WHERE is_base;\n\n-- ─────────────────────── conversions ───────────────────────────────────\nCREATE TABLE IF NOT EXISTS public.plg_inventory_unit_conversions (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n from_unit_id uuid NOT NULL REFERENCES public.plg_inventory_measurement_units(id) ON DELETE CASCADE,\n to_unit_id uuid NOT NULL REFERENCES public.plg_inventory_measurement_units(id) ON DELETE CASCADE,\n factor numeric(20,8) NOT NULL CHECK (factor > 0),\n product_id uuid REFERENCES public.products(id) ON DELETE CASCADE,\n notes text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CHECK (from_unit_id <> to_unit_id)\n);\nSELECT app.scaffold_table('public.plg_inventory_unit_conversions', 'inventory.unit_conversion', 'inventory', false, 'enforce');\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_unit_conversions_key\n ON public.plg_inventory_unit_conversions (tenant_id, from_unit_id, to_unit_id, coalesce(product_id, '00000000-0000-0000-0000-000000000000'::uuid));\nCREATE INDEX IF NOT EXISTS plg_inventory_unit_conversions_product_idx\n ON public.plg_inventory_unit_conversions (tenant_id, product_id) WHERE product_id IS NOT NULL;\n\nREVOKE ALL ON public.plg_inventory_measurement_units, public.plg_inventory_unit_conversions FROM authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_inventory_measurement_units, public.plg_inventory_unit_conversions TO authenticated;\nGRANT ALL ON public.plg_inventory_measurement_units, public.plg_inventory_unit_conversions TO service_role;\nREVOKE ALL ON public.plg_inventory_measurement_units, public.plg_inventory_unit_conversions FROM anon;\n\n-- ─────────────────────── recipe columns → units (guarded FKs) ──────────\n-- Recipes are out of scope (PRD 06), but their unit columns should point at the\n-- units table where the data allows it: added only when no orphan value exists.\nDO $$\nBEGIN\n IF to_regclass('public.plg_inventory_recipes') IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipes_yield_unit_fk' AND conrelid = 'public.plg_inventory_recipes'::regclass)\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_recipes r\n WHERE r.yield_unit_id IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_measurement_units u WHERE u.id = r.yield_unit_id)) THEN\n ALTER TABLE public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_yield_unit_fk FOREIGN KEY (yield_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\n IF to_regclass('public.plg_inventory_recipe_ingredients') IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_ingredients_unit_fk' AND conrelid = 'public.plg_inventory_recipe_ingredients'::regclass)\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_recipe_ingredients i\n WHERE i.unit_id IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_measurement_units u WHERE u.id = i.unit_id)) THEN\n ALTER TABLE public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_unit_fk FOREIGN KEY (unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\n-- ─────────────────────── the standard units, per tenant ────────────────\nCREATE OR REPLACE FUNCTION public.inventory_seed_measurement_units(p_tenant uuid)\nRETURNS integer\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_n integer := 0;\n v_ins integer;\n v_kg uuid; v_g uuid; v_l uuid; v_ml uuid;\nBEGIN\n IF p_tenant IS NULL THEN RETURN 0; END IF;\n WITH ins AS (\n INSERT INTO public.plg_inventory_measurement_units (tenant_id, name, abbreviation, code, kind, is_base, is_active)\n SELECT p_tenant, s.name, s.abbr, s.code, s.kind, s.is_base, true\n FROM (VALUES\n ('Unidade', 'un', 'un', 'unit', true),\n ('Caixa', 'cx', 'cx', 'unit', false),\n ('Quilograma', 'kg', 'kg', 'mass', false),\n ('Grama', 'g', 'g', 'mass', true),\n ('Litro', 'L', 'l', 'volume', false),\n ('Mililitro', 'mL', 'ml', 'volume', true)\n ) AS s(name, abbr, code, kind, is_base)\n WHERE NOT EXISTS (SELECT 1 FROM public.plg_inventory_measurement_units u WHERE u.tenant_id = p_tenant AND lower(u.code) = s.code)\n RETURNING 1\n ) SELECT count(*) INTO v_ins FROM ins;\n v_n := v_n + coalesce(v_ins, 0);\n\n SELECT id INTO v_kg FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'kg';\n SELECT id INTO v_g FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'g';\n SELECT id INTO v_l FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'l';\n SELECT id INTO v_ml FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'ml';\n WITH ins AS (\n INSERT INTO public.plg_inventory_unit_conversions (tenant_id, from_unit_id, to_unit_id, factor)\n SELECT p_tenant, c.f, c.t, c.factor\n FROM (VALUES (v_kg, v_g, 1000::numeric), (v_l, v_ml, 1000::numeric)) AS c(f, t, factor)\n WHERE c.f IS NOT NULL AND c.t IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_unit_conversions x\n WHERE x.tenant_id = p_tenant AND x.from_unit_id = c.f AND x.to_unit_id = c.t AND x.product_id IS NULL)\n RETURNING 1\n ) SELECT count(*) INTO v_ins FROM ins;\n RETURN v_n + coalesce(v_ins, 0);\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_seed_measurement_units(uuid) FROM public, anon, authenticated;\nGRANT EXECUTE ON FUNCTION public.inventory_seed_measurement_units(uuid) TO service_role;\n\n-- The session variant: a signed-in manager (inventory.manage) seeds her own tenant.\nCREATE OR REPLACE FUNCTION public.inventory_seed_measurement_units()\nRETURNS integer\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE v_tenant uuid := app.current_tenant_id();\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('inventory.manage') THEN\n RAISE EXCEPTION 'inventory: inventory.manage required' USING ERRCODE = '42501';\n END IF;\n RETURN public.inventory_seed_measurement_units(v_tenant);\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_seed_measurement_units() FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_seed_measurement_units() TO authenticated, service_role;\n\n-- every existing tenant, now\nDO $$\nDECLARE t record;\nBEGIN\n FOR t IN SELECT id FROM public.tenants LOOP\n PERFORM public.inventory_seed_measurement_units(t.id);\n END LOOP;\nEND $$;\n\n-- every new tenant, by trigger\nCREATE OR REPLACE FUNCTION app.trg_inventory_seed_units_for_tenant()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n PERFORM public.inventory_seed_measurement_units(NEW.id);\n RETURN NULL;\nEND $$;\nDROP TRIGGER IF EXISTS tenants_inventory_seed_units ON public.tenants;\nCREATE TRIGGER tenants_inventory_seed_units\n AFTER INSERT ON public.tenants\n FOR EACH ROW EXECUTE FUNCTION app.trg_inventory_seed_units_for_tenant();\n\n-- ─────────────────────── inventory_convert ─────────────────────────────\n-- Resolves qty from one unit to another for a tenant (and optionally a product):\n-- same unit → qty; a product-specific row beats a tenant-wide one; the inverse\n-- of a row is used when only that direction is defined; otherwise one hop through\n-- the base unit of the kind (kg → g → mL is NOT a path: kinds must match).\n-- Raises 22023 when no conversion is defined.\nCREATE OR REPLACE FUNCTION public.inventory_convert(p_tenant uuid, p_product uuid, p_qty numeric, p_from_unit uuid, p_to_unit uuid)\nRETURNS numeric\nLANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_factor numeric;\n v_kind_from text; v_kind_to text;\n v_base uuid;\n v_f1 numeric; v_f2 numeric;\nBEGIN\n IF p_tenant IS NULL OR p_from_unit IS NULL OR p_to_unit IS NULL THEN\n RAISE EXCEPTION 'inventory_convert: tenant, from_unit and to_unit are required' USING ERRCODE = '22023';\n END IF;\n -- a signed-in session converts only within its own tenant\n IF auth.uid() IS NOT NULL AND p_tenant IS DISTINCT FROM app.current_tenant_id() THEN\n RAISE EXCEPTION 'inventory_convert: not your tenant' USING ERRCODE = '42501';\n END IF;\n IF p_from_unit = p_to_unit THEN RETURN p_qty; END IF;\n\n -- direct (product-specific first, then tenant-wide)\n SELECT c.factor INTO v_factor FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND c.from_unit_id = p_from_unit AND c.to_unit_id = p_to_unit\n AND (c.product_id = p_product OR c.product_id IS NULL)\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_factor IS NOT NULL THEN RETURN p_qty * v_factor; END IF;\n -- inverse\n SELECT c.factor INTO v_factor FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND c.from_unit_id = p_to_unit AND c.to_unit_id = p_from_unit\n AND (c.product_id = p_product OR c.product_id IS NULL)\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_factor IS NOT NULL THEN RETURN p_qty / v_factor; END IF;\n\n -- one hop through the base unit of the (shared) kind\n SELECT kind INTO v_kind_from FROM public.plg_inventory_measurement_units WHERE id = p_from_unit AND tenant_id = p_tenant;\n SELECT kind INTO v_kind_to FROM public.plg_inventory_measurement_units WHERE id = p_to_unit AND tenant_id = p_tenant;\n IF v_kind_from IS NULL OR v_kind_to IS NULL OR v_kind_from <> v_kind_to THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n SELECT id INTO v_base FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND kind = v_kind_from AND is_base;\n IF v_base IS NULL OR v_base IN (p_from_unit, p_to_unit) THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n -- from → base\n SELECT CASE WHEN c.from_unit_id = p_from_unit THEN c.factor ELSE 1 / c.factor END INTO v_f1\n FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND (c.product_id = p_product OR c.product_id IS NULL)\n AND ((c.from_unit_id = p_from_unit AND c.to_unit_id = v_base) OR (c.from_unit_id = v_base AND c.to_unit_id = p_from_unit))\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n -- base → to\n SELECT CASE WHEN c.from_unit_id = v_base THEN c.factor ELSE 1 / c.factor END INTO v_f2\n FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND (c.product_id = p_product OR c.product_id IS NULL)\n AND ((c.from_unit_id = v_base AND c.to_unit_id = p_to_unit) OR (c.from_unit_id = p_to_unit AND c.to_unit_id = v_base))\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_f1 IS NULL OR v_f2 IS NULL THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n RETURN p_qty * v_f1 * v_f2;\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_convert(uuid, uuid, numeric, uuid, uuid) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_convert(uuid, uuid, numeric, uuid, uuid) TO authenticated, service_role;\n\nCOMMENT ON TABLE public.plg_inventory_unit_conversions IS\n 'from_unit → to_unit × factor, tenant-wide (product_id NULL) or product-specific (a 250 mL bottle: bottle → mL × 250). Resolved by public.inventory_convert().';\n`\n\nexport const MIGRATION_014_INVENTORY_POSITIONS_AND_VIEWS = `-- ============================================================================\n-- 014_inventory_positions_and_views.sql — the ONE writer of balances and the\n-- read views (PRD 06 R1/R4 / #143).\n--\n-- A movement row is normalized BEFORE INSERT (locations checked against the\n-- tenant, unit_id and total_cost derived, actor defaulted) and applied to the\n-- positions AFTER INSERT: +quantity at (product, source_location, batch,\n-- expiry), −quantity at destination for a transfer / reversed transfer. Cost on\n-- a position is the moving weighted average of what came in; a transfer carries\n-- the source position's cost, so cost is preserved across units.\n--\n-- Balances are read through views (security_invoker: the caller's RLS on the\n-- scaffolded tables decides what she sees):\n-- v_inventory_balances per (product, location, batch, expiry) + reserved/available\n-- v_inventory_product_totals per product\n-- v_inventory_low_stock products at or below their min quantity (settings)\n-- v_inventory_movements the ledger with product / location names\n--\n-- products.stock / products.min_stock stay as one-way MIRRORS (see 005 header).\n-- ============================================================================\n\n-- ─────────────────────── BEFORE INSERT: normalize + validate ───────────\nCREATE OR REPLACE FUNCTION app.inventory_movements_before_insert()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_src record;\n v_dst record;\nBEGIN\n IF NEW.tenant_id IS NULL THEN\n RAISE EXCEPTION 'inventory: movement without tenant' USING ERRCODE = '22023';\n END IF;\n IF NEW.source_location_id IS NULL THEN\n RAISE EXCEPTION 'inventory: movement without a source location' USING ERRCODE = '22023';\n END IF;\n SELECT id, tenant_id, unit_id, is_active INTO v_src FROM public.plg_inventory_stock_locations WHERE id = NEW.source_location_id;\n IF v_src.id IS NULL OR v_src.tenant_id <> NEW.tenant_id THEN\n RAISE EXCEPTION 'inventory: source location % does not belong to the tenant', NEW.source_location_id USING ERRCODE = '22023';\n END IF;\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT id, tenant_id, unit_id, is_active INTO v_dst FROM public.plg_inventory_stock_locations WHERE id = NEW.destination_location_id;\n IF v_dst.id IS NULL OR v_dst.tenant_id <> NEW.tenant_id THEN\n RAISE EXCEPTION 'inventory: destination location % does not belong to the tenant', NEW.destination_location_id USING ERRCODE = '22023';\n END IF;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.products p WHERE p.id = NEW.product_id AND p.tenant_id = NEW.tenant_id) THEN\n RAISE EXCEPTION 'inventory: product % does not belong to the tenant', NEW.product_id USING ERRCODE = '22023';\n END IF;\n -- the unit of the ledger row is the unit of the location whose stock moves first\n NEW.unit_id := v_src.unit_id;\n NEW.unit_cost := coalesce(NEW.unit_cost, 0);\n NEW.total_cost := abs(NEW.quantity) * NEW.unit_cost;\n NEW.user_id := coalesce(NEW.user_id, auth.uid());\n NEW.movement_date := coalesce(NEW.movement_date, current_date);\n NEW.metadata := coalesce(NEW.metadata, '{}'::jsonb);\n NEW.batch_number := nullif(btrim(NEW.batch_number), '');\n RETURN NEW;\nEND $$;\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_before_insert ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_before_insert\n BEFORE INSERT ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_before_insert();\n\n-- ─────────────────────── apply one effect to one position ──────────────\n-- Upserts the position identity and returns the resulting (quantity, unit_cost).\n-- Positive effect: moving weighted average with p_unit_cost. Negative effect:\n-- cost unchanged; refuses to go below zero (23514) — the RPCs check first with a\n-- friendlier message, this is the last line of defense.\nCREATE OR REPLACE FUNCTION app.inventory_apply_to_position(\n p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date,\n p_effect numeric, p_unit_cost numeric, p_measurement_unit uuid,\n OUT o_quantity numeric, OUT o_unit_cost numeric)\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_unit uuid;\n v_pos record;\n v_new_qty numeric;\n v_new_cost numeric;\nBEGIN\n SELECT l.unit_id INTO v_unit FROM public.plg_inventory_stock_locations l WHERE l.id = p_location AND l.tenant_id = p_tenant;\n SELECT p.id, p.quantity, p.unit_cost INTO v_pos\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)\n FOR UPDATE;\n IF v_pos.id IS NULL THEN\n IF p_effect < 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock (no position for product % at location %)', p_product, p_location USING ERRCODE = '23514';\n END IF;\n INSERT INTO public.plg_inventory_stock_positions\n (tenant_id, unit_id, product_id, stock_location_id, batch_number, expiration_date, quantity, unit_cost, measurement_unit_id)\n VALUES (p_tenant, v_unit, p_product, p_location, p_batch, p_expiry, p_effect, coalesce(p_unit_cost, 0), p_measurement_unit)\n RETURNING plg_inventory_stock_positions.quantity, plg_inventory_stock_positions.unit_cost INTO o_quantity, o_unit_cost;\n RETURN;\n END IF;\n v_new_qty := v_pos.quantity + p_effect;\n IF v_new_qty < 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock (product % at location %: % on hand, % requested)', p_product, p_location, v_pos.quantity, -p_effect USING ERRCODE = '23514';\n END IF;\n IF p_effect > 0 AND v_new_qty > 0 THEN\n v_new_cost := (v_pos.quantity * v_pos.unit_cost + p_effect * coalesce(p_unit_cost, v_pos.unit_cost)) / v_new_qty;\n ELSE\n v_new_cost := v_pos.unit_cost;\n END IF;\n UPDATE public.plg_inventory_stock_positions p\n SET quantity = v_new_qty, unit_cost = round(v_new_cost, 4), unit_id = v_unit,\n measurement_unit_id = coalesce(p.measurement_unit_id, p_measurement_unit)\n WHERE p.id = v_pos.id\n RETURNING p.quantity, p.unit_cost INTO o_quantity, o_unit_cost;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_apply_to_position(uuid, uuid, uuid, text, date, numeric, numeric, uuid) FROM public, anon, authenticated;\n\n-- ─────────────────────── the products.stock mirror ─────────────────────\n-- One-way, inventory → products.stock = Σ positions of the product. Guarded on\n-- the column still existing so a later catalog decision to drop it costs nothing here.\nCREATE OR REPLACE FUNCTION app.inventory_refresh_product_stock(p_tenant uuid, p_product uuid)\nRETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'stock') THEN\n EXECUTE 'UPDATE public.products p SET stock = s.qty FROM (SELECT coalesce(sum(quantity), 0) AS qty FROM public.plg_inventory_stock_positions x WHERE x.tenant_id = $1 AND x.product_id = $2) s WHERE p.id = $2 AND p.tenant_id = $1 AND p.stock IS DISTINCT FROM s.qty'\n USING p_tenant, p_product;\n END IF;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_refresh_product_stock(uuid, uuid) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_refresh_product_min_stock(p_tenant uuid, p_product uuid)\nRETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'min_stock') THEN\n EXECUTE 'UPDATE public.products p SET min_stock = s.q FROM (SELECT (SELECT min_quantity FROM public.plg_inventory_product_settings x WHERE x.tenant_id = $1 AND x.product_id = $2 AND x.unit_id IS NULL) AS q) s WHERE p.id = $2 AND p.tenant_id = $1 AND p.min_stock IS DISTINCT FROM s.q'\n USING p_tenant, p_product;\n END IF;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_refresh_product_min_stock(uuid, uuid) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.trg_inventory_product_settings_mirror()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF TG_OP = 'DELETE' THEN\n PERFORM app.inventory_refresh_product_min_stock(OLD.tenant_id, OLD.product_id);\n RETURN OLD;\n END IF;\n PERFORM app.inventory_refresh_product_min_stock(NEW.tenant_id, NEW.product_id);\n RETURN NEW;\nEND $$;\nDROP TRIGGER IF EXISTS plg_inventory_product_settings_mirror ON public.plg_inventory_product_settings;\nCREATE TRIGGER plg_inventory_product_settings_mirror\n AFTER INSERT OR UPDATE OR DELETE ON public.plg_inventory_product_settings\n FOR EACH ROW EXECUTE FUNCTION app.trg_inventory_product_settings_mirror();\n\n-- ─────────────────────── AFTER INSERT: the writer ──────────────────────\nCREATE OR REPLACE FUNCTION app.inventory_movements_after_insert()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_prev text := coalesce(current_setting('fayz.inventory_internal', true), 'off');\n r record;\nBEGIN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.source_location_id, NEW.batch_number, NEW.expiration_date,\n NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.destination_location_id, NEW.batch_number, NEW.expiration_date,\n -NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n END IF;\n PERFORM app.inventory_refresh_product_stock(NEW.tenant_id, NEW.product_id);\n PERFORM set_config('fayz.inventory_internal', v_prev, true);\n RETURN NULL;\nEND $$;\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_after_insert ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_after_insert\n AFTER INSERT ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_after_insert();\n\n-- ─────────────────────── views ─────────────────────────────────────────\n-- Product name/sku for the ledger reader: the caller's own tenant only, but not\n-- through products' row policies — a reader of the stock ledger sees which\n-- product moved even where the catalog's legacy RLS (tenant_members) would hide\n-- the row from her. Nothing else of the product is exposed.\nCREATE OR REPLACE FUNCTION app.inventory_product_label(p_product uuid)\nRETURNS TABLE (name text, sku text)\nLANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$\n SELECT p.name, p.sku FROM public.products p\n WHERE p.id = p_product AND p.tenant_id = app.current_tenant_id();\n$$;\nREVOKE ALL ON FUNCTION app.inventory_product_label(uuid) FROM public, anon;\nGRANT EXECUTE ON FUNCTION app.inventory_product_label(uuid) TO authenticated, service_role;\n\nDROP VIEW IF EXISTS public.v_inventory_low_stock;\nDROP VIEW IF EXISTS public.v_inventory_product_totals;\nDROP VIEW IF EXISTS public.v_inventory_balances;\nDROP VIEW IF EXISTS public.v_inventory_movements;\n\nCREATE VIEW public.v_inventory_balances WITH (security_invoker = true) AS\n SELECT p.id,\n p.tenant_id,\n p.unit_id,\n p.product_id,\n pl.name AS product_name,\n pl.sku AS product_sku,\n p.stock_location_id,\n l.name AS location_name,\n p.batch_number,\n p.expiration_date,\n p.quantity,\n coalesce(r.reserved, 0)::numeric AS reserved_quantity,\n (p.quantity - coalesce(r.reserved, 0))::numeric AS available_quantity,\n p.unit_cost,\n (p.quantity * p.unit_cost)::numeric AS total_value,\n p.measurement_unit_id,\n mu.code AS measurement_unit_code,\n p.created_at,\n p.updated_at\n FROM public.plg_inventory_stock_positions p\n LEFT JOIN public.plg_inventory_stock_locations l ON l.id = p.stock_location_id\n LEFT JOIN public.plg_inventory_measurement_units mu ON mu.id = p.measurement_unit_id\n LEFT JOIN LATERAL app.inventory_product_label(p.product_id) pl ON true\n LEFT JOIN LATERAL (\n SELECT sum(x.quantity) AS reserved\n FROM public.plg_inventory_reservations x\n WHERE x.tenant_id = p.tenant_id AND x.product_id = p.product_id AND x.stock_location_id = p.stock_location_id\n AND coalesce(x.batch_number, '') = coalesce(p.batch_number, '')\n AND coalesce(x.expiration_date, 'infinity'::date) = coalesce(p.expiration_date, 'infinity'::date)\n AND x.status = 'reserved'\n ) r ON true;\n\nCREATE VIEW public.v_inventory_product_totals WITH (security_invoker = true) AS\n SELECT b.tenant_id,\n b.product_id,\n max(b.product_name) AS product_name,\n max(b.product_sku) AS product_sku,\n sum(b.quantity)::numeric AS on_hand,\n sum(b.reserved_quantity)::numeric AS reserved_quantity,\n sum(b.available_quantity)::numeric AS available_quantity,\n CASE WHEN sum(b.quantity) > 0 THEN round(sum(b.quantity * b.unit_cost) / sum(b.quantity), 4) ELSE max(b.unit_cost) END::numeric AS avg_unit_cost,\n sum(b.total_value)::numeric AS total_value,\n count(DISTINCT b.stock_location_id)::integer AS location_count,\n count(*)::integer AS position_count,\n min(b.expiration_date) AS next_expiration,\n max(b.updated_at) AS updated_at\n FROM public.v_inventory_balances b\n GROUP BY b.tenant_id, b.product_id;\n\n-- Low stock: tenant-wide (per product, unit_id NULL: settings row without a unit)\n-- and per unit (settings row for that unit, else the tenant-wide minimum).\nCREATE VIEW public.v_inventory_low_stock WITH (security_invoker = true) AS\n WITH per_unit AS (\n SELECT b.tenant_id, b.product_id, b.unit_id, sum(b.quantity) AS on_hand, sum(b.available_quantity) AS available_quantity\n FROM public.v_inventory_balances b GROUP BY b.tenant_id, b.product_id, b.unit_id\n ),\n tenant_wide AS (\n SELECT b.tenant_id, b.product_id, NULL::uuid AS unit_id, sum(b.quantity) AS on_hand, sum(b.available_quantity) AS available_quantity\n FROM public.v_inventory_balances b GROUP BY b.tenant_id, b.product_id\n ),\n scopes AS (SELECT * FROM per_unit UNION ALL SELECT * FROM tenant_wide),\n settings AS (\n SELECT s.tenant_id, s.product_id, s.unit_id, s.min_quantity, s.max_quantity\n FROM public.plg_inventory_product_settings s\n )\n SELECT s.tenant_id, s.product_id, pl.name AS product_name, pl.sku AS product_sku, s.unit_id,\n coalesce(sc.on_hand, 0)::numeric AS on_hand,\n coalesce(sc.available_quantity, 0)::numeric AS available_quantity,\n s.min_quantity, s.max_quantity,\n (s.min_quantity - coalesce(sc.on_hand, 0))::numeric AS shortfall\n FROM settings s\n LEFT JOIN scopes sc ON sc.tenant_id = s.tenant_id AND sc.product_id = s.product_id AND sc.unit_id IS NOT DISTINCT FROM s.unit_id\n LEFT JOIN LATERAL app.inventory_product_label(s.product_id) pl ON true\n WHERE s.min_quantity > 0 AND coalesce(sc.on_hand, 0) <= s.min_quantity;\n\nCREATE VIEW public.v_inventory_movements WITH (security_invoker = true) AS\n SELECT m.id,\n m.tenant_id,\n m.unit_id,\n m.product_id,\n pl.name AS product_name,\n pl.sku AS product_sku,\n m.kind,\n -- the SDK's historical label, for readers that still speak it\n CASE m.kind WHEN 'in' THEN 'entry' WHEN 'out' THEN CASE WHEN m.reason ILIKE 'loss%' OR m.document_type = 'loss' THEN 'loss' ELSE 'exit' END\n WHEN 'transfer' THEN 'transfer' WHEN 'adjust' THEN 'adjustment' WHEN 'reverse' THEN 'adjustment' END AS movement_type,\n m.quantity,\n abs(m.quantity) AS abs_quantity,\n m.unit_cost,\n m.total_cost,\n m.source_location_id,\n sl.name AS source_location_name,\n m.destination_location_id,\n dl.name AS destination_location_name,\n m.batch_number,\n m.expiration_date,\n m.measurement_unit_id,\n mu.code AS measurement_unit_code,\n m.supplier_id,\n sp.name AS supplier_name,\n m.document_type,\n m.document_number,\n m.reason,\n m.notes,\n m.movement_date,\n m.user_id,\n m.reverses_movement_id,\n m.idempotency_key,\n m.line_no,\n m.operation_id,\n m.source_item_type,\n m.source_item_id,\n m.metadata,\n m.created_at\n FROM public.plg_inventory_stock_movements m\n LEFT JOIN LATERAL app.inventory_product_label(m.product_id) pl ON true\n LEFT JOIN public.plg_inventory_stock_locations sl ON sl.id = m.source_location_id\n LEFT JOIN public.plg_inventory_stock_locations dl ON dl.id = m.destination_location_id\n LEFT JOIN public.plg_inventory_measurement_units mu ON mu.id = m.measurement_unit_id\n LEFT JOIN public.people sp ON sp.id = m.supplier_id;\n\nGRANT SELECT ON public.v_inventory_balances, public.v_inventory_product_totals, public.v_inventory_low_stock, public.v_inventory_movements\n TO authenticated, service_role;\nREVOKE ALL ON public.v_inventory_balances, public.v_inventory_product_totals, public.v_inventory_low_stock, public.v_inventory_movements FROM anon;\n\nCOMMENT ON VIEW public.v_inventory_balances IS 'Balances per (product, location, batch, expiry) with reserved/available. security_invoker: the caller sees the units she has access to (inventory.read).';\nCOMMENT ON VIEW public.v_inventory_product_totals IS 'Balances per product across the units the caller sees. Replaces products.stock as the read model.';\nCOMMENT ON VIEW public.v_inventory_low_stock IS 'Products at or below the min quantity of plg_inventory_product_settings (tenant-wide row: unit_id NULL; per-unit rows).';\nCOMMENT ON VIEW public.v_inventory_movements IS 'The append-only ledger with names. movement_type is the SDK legacy label (entry/exit/loss/adjustment/transfer); kind is canonical.';\n`\n\nexport const MIGRATION_015_INVENTORY_RPCS = `-- ============================================================================\n-- 015_inventory_rpcs.sql — the write surface of the inventory contract\n-- (PRD 06 R1/R3 / #143). Six RPCs, all SECURITY DEFINER SET search_path = '':\n--\n-- inventory_receive(location, lines, document, key) 'in' — initial load without invoice, purchase, …\n-- inventory_transfer(from, to, lines, key) 'transfer' — cost preserved\n-- inventory_adjust(location, lines, reason, key) 'adjust' — reason mandatory\n-- inventory_reserve(source_type, source_id, lines, key) reservation rows (no movement yet)\n-- inventory_confirm(key) one 'out' per reservation, exactly once\n-- inventory_reverse(key, reason) releases reservations / writes reversals\n--\n-- Actor = auth.uid(); tenant = app.current_tenant_id() (never a parameter);\n-- every touched location must be in the caller's unit scope (app.has_unit) and\n-- the action permission is checked against that unit (app.has_permission with\n-- inventory.create / inventory.edit — manage implies both). Denied → 42501.\n-- Idempotent: every call records (tenant, kind, key) in plg_inventory_operations;\n-- replaying a key returns the stored result and has no second effect. A key not\n-- given is generated for receive/transfer/adjust; for reserve it defaults to\n-- '<source_type>:<source_id>' — the source item IS the key. Each mutating call\n-- writes one row into public.audit_logs.\n--\n-- Lines carry an optional measurement_unit_id: when it differs from the\n-- product's stock unit (plg_inventory_product_settings.measurement_unit_id) the\n-- quantity is converted through public.inventory_convert — the bottle ↔ mL case.\n--\n-- Server-plane callers (edge functions) impersonate the already-verified actor\n-- by setting request.jwt.claims locally, as the agent RPCs of the spine do —\n-- there is no service_role bypass of the permission checks.\n-- ============================================================================\n\n-- ─────────────────────── internal helpers (schema app) ─────────────────\nCREATE OR REPLACE FUNCTION app.inventory_require_tenant()\nRETURNS uuid LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = '' AS $$\nDECLARE v_tenant uuid := app.current_tenant_id();\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n RETURN v_tenant;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_require_tenant() FROM public, anon, authenticated;\n\n-- The location must exist in the tenant, be in the caller's units, and the\n-- caller must hold p_perm for its unit. Returns the location's unit.\nCREATE OR REPLACE FUNCTION app.inventory_authorize_location(p_tenant uuid, p_location uuid, p_perm text)\nRETURNS uuid LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = '' AS $$\nDECLARE v_loc record;\nBEGIN\n IF p_location IS NULL THEN\n RAISE EXCEPTION 'inventory: a stock location is required' USING ERRCODE = '22023';\n END IF;\n SELECT id, unit_id, is_active INTO v_loc FROM public.plg_inventory_stock_locations WHERE id = p_location AND tenant_id = p_tenant;\n -- unknown, another tenant's, or outside the caller's units: one answer, no leak\n IF v_loc.id IS NULL OR NOT app.has_unit(v_loc.unit_id) THEN\n RAISE EXCEPTION 'inventory: no access to stock location %', p_location USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission(p_perm, v_loc.unit_id) THEN\n RAISE EXCEPTION 'inventory: % required at the unit of stock location %', p_perm, p_location USING ERRCODE = '42501';\n END IF;\n RETURN v_loc.unit_id;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_authorize_location(uuid, uuid, text) FROM public, anon, authenticated;\n\n-- Start an operation: returns the new operation id, or the stored result of a\n-- previous call with the same (kind, key) — the caller then returns it as-is.\nCREATE OR REPLACE FUNCTION app.inventory_begin_operation(p_tenant uuid, p_kind text, p_key text, p_request jsonb, OUT op_id uuid, OUT existing jsonb)\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n -- from here to inventory_finish_operation the ledger tables accept writes\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n INSERT INTO public.plg_inventory_operations (tenant_id, kind, idempotency_key, actor_id, request)\n VALUES (p_tenant, p_kind, p_key, auth.uid(), coalesce(p_request, '{}'::jsonb))\n ON CONFLICT (tenant_id, kind, idempotency_key) DO NOTHING\n RETURNING id INTO op_id;\n IF op_id IS NULL THEN\n SELECT result INTO existing FROM public.plg_inventory_operations\n WHERE tenant_id = p_tenant AND kind = p_kind AND idempotency_key = p_key;\n IF existing IS NULL THEN\n -- a visible row without a result can only be a call that failed after\n -- committing nothing — impossible in one transaction — or a concurrent\n -- call still in flight after the wait; refuse rather than double-apply\n RAISE EXCEPTION 'inventory: operation % is still in progress', p_key USING ERRCODE = '55P03';\n END IF;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n END IF;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_begin_operation(uuid, text, text, jsonb) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_finish_operation(p_tenant uuid, p_op uuid, p_kind text, p_key text, p_result jsonb, p_audit jsonb)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n UPDATE public.plg_inventory_operations SET status = 'done', result = p_result WHERE id = p_op;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n INSERT INTO public.audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant, auth.uid(), 'inventory.' || p_kind, 'inventory.operation', p_op::text,\n jsonb_build_object('idempotency_key', p_key) || coalesce(p_audit, '{}'::jsonb));\n RETURN p_result;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_finish_operation(uuid, uuid, text, text, jsonb, jsonb) FROM public, anon, authenticated;\n\n-- A validated line: product in tenant, quantity in the required range (mode\n-- 'positive' | 'signed' | 'absolute'), expressed in the product's stock unit\n-- (converted when the line names another unit).\nCREATE OR REPLACE FUNCTION app.inventory_parse_line(p_tenant uuid, p_line jsonb, p_mode text DEFAULT 'positive',\n OUT product_id uuid, OUT quantity numeric, OUT unit_cost numeric, OUT batch_number text, OUT expiration_date date,\n OUT measurement_unit_id uuid, OUT declared jsonb, OUT notes text)\nLANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_product uuid;\n v_declared_unit uuid;\n v_stock_unit uuid;\n v_declared_qty numeric;\n v_qty numeric;\n v_cost numeric;\n v_batch text;\n v_expiry date;\nBEGIN\n BEGIN\n v_product := (p_line->>'product_id')::uuid;\n v_declared_qty := coalesce((p_line->>'quantity')::numeric, (p_line->>'delta')::numeric);\n v_cost := (p_line->>'unit_cost')::numeric;\n v_batch := nullif(btrim(coalesce(p_line->>'batch_number', p_line->>'batch', '')), '');\n v_expiry := coalesce((p_line->>'expiration_date')::date, (p_line->>'expiry')::date);\n v_declared_unit := (p_line->>'measurement_unit_id')::uuid;\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid line %: %', p_line, SQLERRM USING ERRCODE = '22023';\n END;\n IF v_product IS NULL THEN\n RAISE EXCEPTION 'inventory: line without product_id: %', p_line USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.products p WHERE p.id = v_product AND p.tenant_id = p_tenant) THEN\n RAISE EXCEPTION 'inventory: product % not found in this tenant', v_product USING ERRCODE = '22023';\n END IF;\n IF v_declared_qty IS NULL\n OR (p_mode = 'positive' AND v_declared_qty <= 0)\n OR (p_mode = 'signed' AND v_declared_qty = 0)\n OR (p_mode = 'absolute' AND v_declared_qty < 0) THEN\n RAISE EXCEPTION 'inventory: quantity must be % (line %)',\n CASE p_mode WHEN 'positive' THEN 'positive' WHEN 'signed' THEN 'non-zero' ELSE 'zero or positive' END, p_line USING ERRCODE = '22023';\n END IF;\n IF v_cost IS NOT NULL AND v_cost < 0 THEN\n RAISE EXCEPTION 'inventory: unit_cost cannot be negative (line %)', p_line USING ERRCODE = '22023';\n END IF;\n SELECT s.measurement_unit_id INTO v_stock_unit\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = p_tenant AND s.product_id = v_product AND s.unit_id IS NULL;\n v_qty := v_declared_qty;\n declared := '{}'::jsonb;\n IF v_declared_unit IS NOT NULL AND v_stock_unit IS NOT NULL AND v_declared_unit <> v_stock_unit THEN\n v_qty := public.inventory_convert(p_tenant, v_product, v_declared_qty, v_declared_unit, v_stock_unit);\n -- the cost was per declared unit; the ledger keeps cost per stock unit\n IF v_cost IS NOT NULL AND v_qty <> 0 THEN\n v_cost := round(v_cost * v_declared_qty / v_qty, 4);\n END IF;\n declared := jsonb_build_object('declared_quantity', v_declared_qty, 'declared_unit_id', v_declared_unit,\n 'declared_unit_cost', (p_line->>'unit_cost')::numeric);\n END IF;\n product_id := v_product;\n quantity := v_qty;\n unit_cost := v_cost;\n batch_number := v_batch;\n expiration_date := v_expiry;\n measurement_unit_id := coalesce(v_stock_unit, v_declared_unit);\n notes := p_line->>'notes';\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_parse_line(uuid, jsonb, text) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_movement_json(p_id uuid)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$\n SELECT jsonb_build_object(\n 'id', m.id, 'line_no', m.line_no, 'kind', m.kind, 'product_id', m.product_id, 'quantity', m.quantity,\n 'unit_cost', m.unit_cost, 'total_cost', m.total_cost,\n 'source_location_id', m.source_location_id, 'destination_location_id', m.destination_location_id,\n 'batch_number', m.batch_number, 'expiration_date', m.expiration_date,\n 'measurement_unit_id', m.measurement_unit_id, 'reverses_movement_id', m.reverses_movement_id,\n 'source_item_type', m.source_item_type, 'source_item_id', m.source_item_id)\n FROM public.plg_inventory_stock_movements m WHERE m.id = p_id;\n$$;\nREVOKE ALL ON FUNCTION app.inventory_movement_json(uuid) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_position_json(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$\n SELECT coalesce((\n SELECT jsonb_build_object('product_id', p.product_id, 'stock_location_id', p.stock_location_id, 'unit_id', p.unit_id,\n 'batch_number', p.batch_number, 'expiration_date', p.expiration_date,\n 'quantity', p.quantity, 'unit_cost', p.unit_cost)\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)),\n jsonb_build_object('product_id', p_product, 'stock_location_id', p_location, 'batch_number', p_batch, 'expiration_date', p_expiry, 'quantity', 0, 'unit_cost', 0));\n$$;\nREVOKE ALL ON FUNCTION app.inventory_position_json(uuid, uuid, uuid, text, date) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_reservation_json(p_id uuid)\nRETURNS jsonb LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$\n SELECT jsonb_build_object(\n 'id', r.id, 'line_no', r.line_no, 'status', r.status, 'source_type', r.source_type, 'source_id', r.source_id,\n 'product_id', r.product_id, 'stock_location_id', r.stock_location_id, 'quantity', r.quantity,\n 'batch_number', r.batch_number, 'expiration_date', r.expiration_date,\n 'movement_id', r.movement_id, 'reversal_movement_id', r.reversal_movement_id)\n FROM public.plg_inventory_reservations r WHERE r.id = p_id;\n$$;\nREVOKE ALL ON FUNCTION app.inventory_reservation_json(uuid) FROM public, anon, authenticated;\n\n-- available = on hand − open reservations at the same position identity\nCREATE OR REPLACE FUNCTION app.inventory_available(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date)\nRETURNS numeric LANGUAGE sql STABLE SECURITY DEFINER SET search_path = '' AS $$\n SELECT coalesce((SELECT p.quantity FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)), 0)\n - coalesce((SELECT sum(r.quantity) FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.product_id = p_product AND r.stock_location_id = p_location\n AND coalesce(r.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(r.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)\n AND r.status = 'reserved'), 0);\n$$;\nREVOKE ALL ON FUNCTION app.inventory_available(uuid, uuid, uuid, text, date) FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION app.inventory_check_lines(p_lines jsonb)\nRETURNS void LANGUAGE plpgsql IMMUTABLE AS $$\nBEGIN\n IF p_lines IS NULL OR jsonb_typeof(p_lines) <> 'array' OR jsonb_array_length(p_lines) = 0 THEN\n RAISE EXCEPTION 'inventory: lines must be a non-empty JSON array' USING ERRCODE = '22023';\n END IF;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_check_lines(jsonb) FROM public, anon, authenticated;\n\n-- ═══════════════════════════ inventory_receive ═══════════════════════════\n-- lines: [{product_id, quantity, unit_cost?, batch_number?, expiration_date?, measurement_unit_id?, notes?}]\n-- document: {type?: 'initial_load'|'invoice'|'purchase'|'return'|…, ref?, supplier_id?, date?, notes?}\nCREATE OR REPLACE FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb DEFAULT '{}'::jsonb, p_idempotency_key text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'receive:' || gen_random_uuid()::text);\n v_op record;\n v_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_doc jsonb := coalesce(p_document, '{}'::jsonb);\n v_supplier uuid;\n v_date date;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n v_unit := app.inventory_authorize_location(v_tenant, p_location, 'inventory.create');\n BEGIN\n v_supplier := (v_doc->>'supplier_id')::uuid;\n v_date := (v_doc->>'date')::date;\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid document: %', SQLERRM USING ERRCODE = '22023';\n END;\n IF v_supplier IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.people s WHERE s.id = v_supplier AND s.tenant_id = v_tenant) THEN\n RAISE EXCEPTION 'inventory: supplier % not found in this tenant', v_supplier USING ERRCODE = '22023';\n END IF;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'receive', v_key,\n jsonb_build_object('location', p_location, 'lines', p_lines, 'document', v_doc));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n supplier_id, document_type, document_number, notes, movement_date, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'in', v_ln.quantity, coalesce(v_ln.unit_cost, 0), p_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n v_supplier, coalesce(v_doc->>'type', 'manual'), v_doc->>'ref', coalesce(v_ln.notes, v_doc->>'notes'), coalesce(v_date, current_date),\n v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'receive', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'receive', 'idempotency_key', v_key,\n 'location_id', p_location, 'unit_id', v_unit, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('location_id', p_location, 'unit_id', v_unit, 'lines', v_no, 'document_type', coalesce(v_doc->>'type', 'manual')));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_receive(uuid, jsonb, jsonb, text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_receive(uuid, jsonb, jsonb, text) TO authenticated, service_role;\n\n-- ═══════════════════════════ inventory_transfer ══════════════════════════\n-- lines: [{product_id, quantity, batch_number?, expiration_date?, measurement_unit_id?}]\n-- inventory.edit at the source unit, inventory.create at the destination unit;\n-- the movement carries the source position's unit cost (cost preserved).\nCREATE OR REPLACE FUNCTION public.inventory_transfer(p_from_location uuid, p_to_location uuid, p_lines jsonb, p_idempotency_key text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'transfer:' || gen_random_uuid()::text);\n v_op record;\n v_from_unit uuid; v_to_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_avail numeric;\n v_cost numeric;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n IF p_from_location IS NULL OR p_to_location IS NULL OR p_from_location = p_to_location THEN\n RAISE EXCEPTION 'inventory: a transfer needs two different stock locations' USING ERRCODE = '22023';\n END IF;\n v_from_unit := app.inventory_authorize_location(v_tenant, p_from_location, 'inventory.edit');\n v_to_unit := app.inventory_authorize_location(v_tenant, p_to_location, 'inventory.create');\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'transfer', v_key,\n jsonb_build_object('from_location', p_from_location, 'to_location', p_to_location, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n v_avail := app.inventory_available(v_tenant, v_ln.product_id, p_from_location, v_ln.batch_number, v_ln.expiration_date);\n IF v_avail < v_ln.quantity THEN\n RAISE EXCEPTION 'inventory: insufficient stock to transfer product % from location % (% available, % requested)',\n v_ln.product_id, p_from_location, v_avail, v_ln.quantity USING ERRCODE = '23514';\n END IF;\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_from_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, notes, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'transfer', -v_ln.quantity, coalesce(v_cost, 0), p_from_location, p_to_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n 'transfer', v_ln.notes, v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_from_location, v_ln.batch_number, v_ln.expiration_date)\n || app.inventory_position_json(v_tenant, v_ln.product_id, p_to_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'transfer', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'transfer', 'idempotency_key', v_key,\n 'from_location_id', p_from_location, 'to_location_id', p_to_location,\n 'from_unit_id', v_from_unit, 'to_unit_id', v_to_unit, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('from_location_id', p_from_location, 'to_location_id', p_to_location, 'lines', v_no));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_transfer(uuid, uuid, jsonb, text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_transfer(uuid, uuid, jsonb, text) TO authenticated, service_role;\n\n-- ═══════════════════════════ inventory_adjust ════════════════════════════\n-- lines: [{product_id, delta (signed) | set_quantity (absolute), unit_cost?, batch_number?, expiration_date?, measurement_unit_id?}]\n-- reason is mandatory; inventory.edit at the location's unit.\nCREATE OR REPLACE FUNCTION public.inventory_adjust(p_location uuid, p_lines jsonb, p_reason text, p_idempotency_key text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'adjust:' || gen_random_uuid()::text);\n v_reason text := nullif(btrim(p_reason), '');\n v_op record;\n v_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_delta numeric;\n v_current numeric;\n v_target numeric;\n v_cost numeric;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: an adjustment needs a reason' USING ERRCODE = '22023';\n END IF;\n PERFORM app.inventory_check_lines(p_lines);\n v_unit := app.inventory_authorize_location(v_tenant, p_location, 'inventory.edit');\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'adjust', v_key,\n jsonb_build_object('location', p_location, 'lines', p_lines, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n IF v_line ? 'set_quantity' THEN\n -- absolute: turn into a delta against the current position (in the stock unit)\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, (v_line - 'set_quantity') || jsonb_build_object('quantity', v_line->'set_quantity'), 'absolute');\n v_target := v_ln.quantity;\n IF v_target < 0 THEN\n RAISE EXCEPTION 'inventory: set_quantity cannot be negative (line %)', v_line USING ERRCODE = '22023';\n END IF;\n SELECT coalesce(p.quantity, 0) INTO v_current FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n v_delta := v_target - coalesce(v_current, 0);\n IF v_delta = 0 THEN\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n CONTINUE;\n END IF;\n ELSE\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'signed');\n v_delta := v_ln.quantity;\n END IF;\n IF v_delta < 0 THEN\n IF app.inventory_available(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date) < -v_delta THEN\n RAISE EXCEPTION 'inventory: adjustment would take product % at location % below its available quantity',\n v_ln.product_id, p_location USING ERRCODE = '23514';\n END IF;\n END IF;\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, reason, notes, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'adjust', v_delta, coalesce(v_ln.unit_cost, v_cost, 0), p_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n 'adjustment', v_reason, v_ln.notes, v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'adjust', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'adjust', 'idempotency_key', v_key,\n 'location_id', p_location, 'unit_id', v_unit, 'reason', v_reason, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('location_id', p_location, 'unit_id', v_unit, 'reason', v_reason, 'lines', v_no));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_adjust(uuid, jsonb, text, text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_adjust(uuid, jsonb, text, text) TO authenticated, service_role;\n\n-- ═══════════════════════════ inventory_reserve ═══════════════════════════\n-- lines: [{product_id, location_id | stock_location_id, quantity, batch_number?, expiration_date?, measurement_unit_id?}]\n-- Holds stock for a source item (the executed service line, the order item)\n-- without moving it: available = on hand − reserved. inventory.create at each\n-- location's unit. Key defaults to '<source_type>:<source_id>'.\nCREATE OR REPLACE FUNCTION public.inventory_reserve(p_source_type text, p_source_id uuid, p_lines jsonb, p_idempotency_key text DEFAULT NULL)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_source_type text := nullif(btrim(p_source_type), '');\n v_key text;\n v_op record;\n v_line jsonb;\n v_ln record;\n v_loc uuid;\n v_unit uuid;\n v_no integer := 0;\n v_id uuid;\n v_avail numeric;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n IF v_source_type IS NULL OR p_source_id IS NULL THEN\n RAISE EXCEPTION 'inventory: a reservation needs source_type and source_id' USING ERRCODE = '22023';\n END IF;\n v_key := coalesce(nullif(btrim(p_idempotency_key), ''), v_source_type || ':' || p_source_id::text);\n PERFORM app.inventory_check_lines(p_lines);\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'reserve', v_key,\n jsonb_build_object('source_type', v_source_type, 'source_id', p_source_id, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n BEGIN\n v_loc := coalesce((v_line->>'location_id')::uuid, (v_line->>'stock_location_id')::uuid);\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid line %: %', v_line, SQLERRM USING ERRCODE = '22023';\n END;\n v_unit := app.inventory_authorize_location(v_tenant, v_loc, 'inventory.create');\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n v_avail := app.inventory_available(v_tenant, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date);\n IF v_avail < v_ln.quantity THEN\n RAISE EXCEPTION 'inventory: insufficient stock to reserve product % at location % (% available, % requested)',\n v_ln.product_id, v_loc, v_avail, v_ln.quantity USING ERRCODE = '23514';\n END IF;\n INSERT INTO public.plg_inventory_reservations\n (tenant_id, unit_id, idempotency_key, line_no, source_type, source_id, product_id, stock_location_id, batch_number, expiration_date,\n quantity, measurement_unit_id, status, metadata)\n VALUES\n (v_tenant, v_unit, v_key, v_no, v_source_type, p_source_id, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date,\n v_ln.quantity, v_ln.measurement_unit_id, 'reserved', v_ln.declared)\n RETURNING id INTO v_id;\n v_reservations := v_reservations || app.inventory_reservation_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'reserve', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'reserve', 'idempotency_key', v_key,\n 'source_type', v_source_type, 'source_id', p_source_id, 'status', 'reserved',\n 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('source_type', v_source_type, 'source_id', p_source_id, 'lines', v_no));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_reserve(text, uuid, jsonb, text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_reserve(text, uuid, jsonb, text) TO authenticated, service_role;\n\n-- ═══════════════════════════ inventory_confirm ═══════════════════════════\n-- Turns every 'reserved' line of the key into one 'out' movement, exactly once\n-- (compare-and-set on status). inventory.edit at each location's unit — the\n-- second check of RN-EST-01 is who confirms; who approved is recorded.\nCREATE OR REPLACE FUNCTION public.inventory_confirm(p_idempotency_key text)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := nullif(btrim(p_idempotency_key), '');\n v_op record;\n r record;\n v_unit uuid;\n v_id uuid;\n v_cost numeric;\n v_n integer := 0;\n v_movements jsonb := '[]'::jsonb;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_source_type text; v_source_id uuid;\nBEGIN\n IF v_key IS NULL THEN\n RAISE EXCEPTION 'inventory: idempotency_key is required' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key) THEN\n RAISE EXCEPTION 'inventory: no reservation with key % in this tenant', v_key USING ERRCODE = '22023';\n END IF;\n -- authorization first, before the operation row exists\n FOR r IN SELECT DISTINCT stock_location_id FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key LOOP\n PERFORM app.inventory_authorize_location(v_tenant, r.stock_location_id, 'inventory.edit');\n END LOOP;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'confirm', v_key, jsonb_build_object('idempotency_key', v_key));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR r IN SELECT * FROM public.plg_inventory_reservations x\n WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no FOR UPDATE LOOP\n v_source_type := r.source_type; v_source_id := r.source_id;\n IF r.status = 'reserved' THEN\n -- CAS: only the row still reserved becomes a movement\n UPDATE public.plg_inventory_reservations x\n SET status = 'confirmed', confirmed_at = now(), confirmed_by = auth.uid()\n WHERE x.id = r.id AND x.status = 'reserved';\n IF FOUND THEN\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = r.product_id AND p.stock_location_id = r.stock_location_id\n AND coalesce(p.batch_number, '') = coalesce(r.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(r.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, source_item_type, source_item_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'out', -r.quantity, coalesce(v_cost, 0), r.stock_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'consumption', r.source_type || ':' || r.source_id::text, r.source_type, r.source_id, v_key, r.line_no, v_op.op_id,\n coalesce(r.metadata, '{}'::jsonb) || jsonb_build_object('reservation_id', r.id))\n RETURNING id INTO v_id;\n UPDATE public.plg_inventory_reservations x SET movement_id = v_id WHERE x.id = r.id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_n := v_n + 1;\n END IF;\n ELSIF r.status = 'reversed' AND r.movement_id IS NULL THEN\n RAISE EXCEPTION 'inventory: reservation % line % was reversed before confirmation', v_key, r.line_no USING ERRCODE = '55000';\n END IF;\n v_reservations := v_reservations || app.inventory_reservation_json(r.id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.stock_location_id, r.batch_number, r.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm', 'idempotency_key', v_key,\n 'source_type', v_source_type, 'source_id', v_source_id, 'status', 'confirmed',\n 'movements', v_movements, 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('source_type', v_source_type, 'source_id', v_source_id, 'confirmed_lines', v_n));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_confirm(text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_confirm(text) TO authenticated, service_role;\n\n-- ═══════════════════════════ inventory_reverse ═══════════════════════════\n-- Undoes what a key did: open reservations are released; confirmed ones get a\n-- 'reverse' movement (+quantity back at the source location, original cost);\n-- movements of a receive / transfer / adjust key are reversed row by row (a\n-- reversal is a new row pointing back through reverses_movement_id; a row is\n-- reversed at most once). Reason mandatory; inventory.edit at each unit.\nCREATE OR REPLACE FUNCTION public.inventory_reverse(p_idempotency_key text, p_reason text)\nRETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := nullif(btrim(p_idempotency_key), '');\n v_reason text := nullif(btrim(p_reason), '');\n v_op record;\n r record;\n v_id uuid;\n v_n integer := 0;\n v_no integer := 0;\n v_avail numeric;\n v_movements jsonb := '[]'::jsonb;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_had boolean := false;\nBEGIN\n IF v_key IS NULL THEN\n RAISE EXCEPTION 'inventory: idempotency_key is required' USING ERRCODE = '22023';\n END IF;\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: a reversal needs a reason' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key)\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.kind <> 'reverse') THEN\n RAISE EXCEPTION 'inventory: nothing to reverse under key % in this tenant', v_key USING ERRCODE = '22023';\n END IF;\n -- authorization first: every unit touched by the key\n FOR r IN SELECT DISTINCT stock_location_id AS loc FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key\n UNION SELECT DISTINCT source_location_id FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key\n UNION SELECT DISTINCT destination_location_id FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.destination_location_id IS NOT NULL LOOP\n PERFORM app.inventory_authorize_location(v_tenant, r.loc, 'inventory.edit');\n END LOOP;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'reverse', v_key, jsonb_build_object('idempotency_key', v_key, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n -- 1. reservations under the key\n FOR r IN SELECT * FROM public.plg_inventory_reservations x\n WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no FOR UPDATE LOOP\n v_had := true;\n IF r.status = 'reserved' THEN\n UPDATE public.plg_inventory_reservations x SET status = 'reversed', reversed_at = now(), reversed_by = auth.uid(), reason = v_reason\n WHERE x.id = r.id AND x.status = 'reserved';\n v_n := v_n + 1;\n ELSIF r.status = 'confirmed' AND r.movement_id IS NOT NULL THEN\n SELECT m.* INTO STRICT r FROM public.plg_inventory_stock_movements m WHERE m.id = r.movement_id;\n v_no := v_no + 1;\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, reason, source_item_type, source_item_id, reverses_movement_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'reverse', -r.quantity, r.unit_cost, r.source_location_id, r.destination_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'reversal', r.document_number, v_reason, r.source_item_type, r.source_item_id, r.id, 'reverse:' || v_key, v_no, v_op.op_id,\n jsonb_build_object('reversed_movement_id', r.id))\n RETURNING id INTO v_id;\n UPDATE public.plg_inventory_reservations x\n SET status = 'reversed', reversed_at = now(), reversed_by = auth.uid(), reason = v_reason, reversal_movement_id = v_id\n WHERE x.movement_id = r.id AND x.status = 'confirmed';\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_n := v_n + 1;\n END IF;\n END LOOP;\n FOR r IN SELECT * FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no LOOP\n v_reservations := v_reservations || app.inventory_reservation_json(r.id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.stock_location_id, r.batch_number, r.expiration_date);\n END LOOP;\n\n -- 2. plain movements under the key (receive / transfer / adjust), not yet reversed\n IF NOT v_had THEN\n FOR r IN SELECT m.* FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.kind <> 'reverse'\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements x WHERE x.reverses_movement_id = m.id)\n ORDER BY m.line_no, m.created_at LOOP\n -- undoing an 'in' or a transfer's arrival must not go below what is still available\n IF r.quantity > 0 THEN\n v_avail := app.inventory_available(v_tenant, r.product_id, r.source_location_id, r.batch_number, r.expiration_date);\n IF v_avail < r.quantity THEN\n RAISE EXCEPTION 'inventory: cannot reverse movement % — only % of % still available at the source location', r.id, v_avail, r.quantity USING ERRCODE = '23514';\n END IF;\n END IF;\n IF r.destination_location_id IS NOT NULL AND r.quantity < 0 THEN\n v_avail := app.inventory_available(v_tenant, r.product_id, r.destination_location_id, r.batch_number, r.expiration_date);\n IF v_avail < -r.quantity THEN\n RAISE EXCEPTION 'inventory: cannot reverse transfer % — only % of % still available at the destination', r.id, v_avail, -r.quantity USING ERRCODE = '23514';\n END IF;\n END IF;\n v_no := v_no + 1;\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, reason, supplier_id, source_item_type, source_item_id, reverses_movement_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'reverse', -r.quantity, r.unit_cost, r.source_location_id, r.destination_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'reversal', r.document_number, v_reason, r.supplier_id, r.source_item_type, r.source_item_id, r.id, 'reverse:' || v_key, v_no, v_op.op_id,\n jsonb_build_object('reversed_movement_id', r.id, 'reversed_kind', r.kind))\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.source_location_id, r.batch_number, r.expiration_date);\n IF r.destination_location_id IS NOT NULL THEN\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.destination_location_id, r.batch_number, r.expiration_date);\n END IF;\n v_n := v_n + 1;\n END LOOP;\n END IF;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'reverse', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'reverse', 'idempotency_key', v_key, 'reason', v_reason,\n 'status', 'reversed', 'reversed_lines', v_n,\n 'movements', v_movements, 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('reason', v_reason, 'reversed_lines', v_n));\nEND $$;\nREVOKE ALL ON FUNCTION public.inventory_reverse(text, text) FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_reverse(text, text) TO authenticated, service_role;\n`\n\nexport const MIGRATION_016_INVENTORY_LEGACY_BACKFILL = `-- ============================================================================\n-- 016_inventory_legacy_backfill.sql — the catalog's stock columns hand over to\n-- the ledger (PRD 04 R5 / PRD 06 R4 / #143).\n--\n-- Before this slice the inventory TS provider wrote products.stock directly and\n-- products.min_stock was the minimum. Now:\n-- • a product that has NO ledger yet but a positive products.stock gets one\n-- opening 'in' movement (document_type 'legacy_backfill') into the tenant's\n-- oldest active stock location — created as \"Estoque\" at the hq unit when the\n-- tenant has none — so Σ movements = positions = the number people saw;\n-- • a positive products.min_stock without a settings row becomes the tenant-wide\n-- plg_inventory_product_settings.min_quantity.\n-- Products the shop owns (a plg_shop_products row) are skipped: their stock is\n-- the shop ledger's (docs/data/phase-0/06-inventory-base.md, \"convergence\").\n--\n-- Guarded per product on \"no movements and no positions yet\", so a replay after\n-- the first pass — or after any real movement — writes nothing. Both loops are\n-- no-ops when the columns are gone.\n-- ============================================================================\nDO $$\nDECLARE\n v_has_stock boolean := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'stock');\n v_has_min boolean := EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'min_stock');\n v_shop boolean := to_regclass('public.plg_shop_products') IS NOT NULL;\n r record;\n v_loc uuid;\n v_hq uuid;\n v_n integer := 0;\nBEGIN\n IF v_has_stock THEN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n FOR r IN EXECUTE format($q$\n SELECT p.id, p.tenant_id, p.stock, p.cost\n FROM public.products p\n WHERE p.stock IS NOT NULL AND p.stock > 0\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = p.tenant_id AND m.product_id = p.id)\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_positions x WHERE x.tenant_id = p.tenant_id AND x.product_id = p.id)\n %s\n ORDER BY p.tenant_id, p.created_at, p.id\n $q$, CASE WHEN v_shop THEN 'AND NOT EXISTS (SELECT 1 FROM public.plg_shop_products s WHERE s.product_id = p.id OR s.id = p.id)' ELSE '' END)\n LOOP\n SELECT l.id INTO v_loc FROM public.plg_inventory_stock_locations l\n WHERE l.tenant_id = r.tenant_id AND l.is_active AND l.unit_id IS NOT NULL\n ORDER BY l.created_at, l.id LIMIT 1;\n IF v_loc IS NULL THEN\n SELECT u.id INTO v_hq FROM app.units u WHERE u.tenant_id = r.tenant_id AND u.kind = 'hq';\n IF v_hq IS NULL THEN\n RAISE NOTICE 'inventory backfill: tenant % has no stock location and no hq unit — product % keeps its legacy products.stock only', r.tenant_id, r.id;\n CONTINUE;\n END IF;\n INSERT INTO public.plg_inventory_stock_locations (tenant_id, unit_id, name, description, is_active)\n VALUES (r.tenant_id, v_hq, 'Estoque', 'Created by the inventory legacy backfill (009)', true)\n RETURNING id INTO v_loc;\n END IF;\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, document_type, document_number, notes, idempotency_key, line_no)\n VALUES\n (r.tenant_id, r.id, 'in', r.stock, coalesce(r.cost, 0), v_loc, 'legacy_backfill', 'products.stock',\n 'Opening balance copied from products.stock by migration 009', 'legacy_backfill:' || r.id::text, 1)\n ON CONFLICT DO NOTHING;\n v_n := v_n + 1;\n END LOOP;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n IF v_n > 0 THEN\n RAISE NOTICE 'inventory backfill: % product(s) received an opening movement from products.stock', v_n;\n END IF;\n END IF;\n\n IF v_has_min THEN\n EXECUTE $q$\n INSERT INTO public.plg_inventory_product_settings (tenant_id, product_id, min_quantity)\n SELECT p.tenant_id, p.id, p.min_stock\n FROM public.products p\n WHERE p.min_stock IS NOT NULL AND p.min_stock > 0\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_product_settings s WHERE s.tenant_id = p.tenant_id AND s.product_id = p.id AND s.unit_id IS NULL)\n ON CONFLICT DO NOTHING\n $q$;\n END IF;\nEND $$;\n\n-- The columns are mirrors from now on: say so where a DBA looks first.\nDO $$\nBEGIN\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'stock') THEN\n COMMENT ON COLUMN public.products.stock IS 'DEPRECATED mirror (inventory plugin 007): Σ plg_inventory_stock_positions.quantity of the product, refreshed after every movement. Read v_inventory_product_totals; never write.';\n END IF;\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'min_stock') THEN\n COMMENT ON COLUMN public.products.min_stock IS 'DEPRECATED mirror (inventory plugin 007): plg_inventory_product_settings.min_quantity of the tenant-wide row. Write the settings row; never this column.';\n END IF;\nEND $$;\n`\n\nexport const MIGRATION_017_RESERVATION_ONE_PER_SOURCE = `-- 017_reservation_one_per_source.sql\n--\n-- The same order line could be consumed twice. Fix for #203.\n--\n-- #143's criterion is an \"idempotent consumption RPC keyed by SOURCE ITEM\". What\n-- shipped is idempotent by KEY: \\`inventory_reserve\\` only *defaults* its key to\n-- \\`source_type:source_id\\` (008:461), and plg_inventory_reservations_source_idx\n-- (005:371) is a plain index. A caller that passes its own key reserves the same\n-- line again:\n--\n-- inventory_reserve('order_item', <id>, …, key => 'keyA') -> reservation 1\n-- inventory_reserve('order_item', <id>, …, key => 'keyB') -> reservation 2\n-- => 4 units reserved; after confirming both, two 'out' movements for one line\n--\n-- Stock leaves twice for one sale, and because movements are append-only the\n-- correction is a manual reversal.\n--\n-- The source item is the unit of consumption, so it is the unit of uniqueness:\n-- one live reservation per (tenant, source_type, source_id, line_no). A reversed\n-- reservation frees the line again, which is what makes \"reverse, then reserve\n-- afresh\" the way to change a line — not a second reservation next to the first.\n--\n-- Two layers, same as elsewhere in this chain: a trigger that explains itself,\n-- and a partial unique index behind it that a race cannot talk its way past.\n--\n-- Replay-safe. If a pool already double-consumed a line the index creation FAILS\n-- — deliberately: that is stock which left twice, and it needs a human, not a\n-- migration quietly picking a winner.\n\nCREATE OR REPLACE FUNCTION app.inventory_reservation_one_per_source()\nRETURNS trigger LANGUAGE plpgsql SET search_path = '' AS $$\nDECLARE v_existing record;\nBEGIN\n IF NEW.status = 'reversed' THEN\n RETURN NEW;\n END IF;\n SELECT r.id, r.idempotency_key, r.status INTO v_existing\n FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = NEW.tenant_id\n AND r.source_type = NEW.source_type\n AND r.source_id = NEW.source_id\n AND r.line_no = NEW.line_no\n AND r.status <> 'reversed'\n AND r.id <> NEW.id\n LIMIT 1;\n IF FOUND THEN\n RAISE EXCEPTION\n 'inventory: % % line % is already consumed by reservation % (%) — reverse it before reserving again',\n NEW.source_type, NEW.source_id, NEW.line_no, v_existing.id, v_existing.status\n USING ERRCODE = '55000',\n HINT = 'inventory_reserve is idempotent by source item, not by idempotency key: a second key does not buy a second consumption (#203).';\n END IF;\n RETURN NEW;\nEND $$;\nREVOKE ALL ON FUNCTION app.inventory_reservation_one_per_source() FROM public, anon, authenticated;\n\nDROP TRIGGER IF EXISTS plg_inventory_reservations_one_per_source ON public.plg_inventory_reservations;\nCREATE TRIGGER plg_inventory_reservations_one_per_source\n BEFORE INSERT OR UPDATE OF status, source_type, source_id, line_no\n ON public.plg_inventory_reservations\n FOR EACH ROW EXECUTE FUNCTION app.inventory_reservation_one_per_source();\n\n-- The backstop the trigger cannot be: two concurrent reserves both read \"no\n-- existing row\" and both insert. The index is what makes the second one fail.\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_reservations_one_live_per_source_uidx\n ON public.plg_inventory_reservations (tenant_id, source_type, source_id, line_no)\n WHERE status <> 'reversed';\n`\n\nexport const MIGRATION_018_SCOPE_LOCALITY = `-- The inventory tables declare what unit_id means on them (#225). See\n-- plugin-financial 028 for why this cannot live in core 126.\n--\n-- Stock happens somewhere: a location, a movement, a position and a reservation\n-- each belong to exactly one branch. Measurement units, unit conversions,\n-- product settings and the idempotency ledger are network configuration or\n-- bookkeeping and stay unit_optional.\n-- WHERE THE UNIT COMES FROM ON A POOL THAT PREDATES THE QUESTION. Declaring a\n-- table \\`unit\\` enforced refuses it while any row still answers NULL, and a pool\n-- with years of stock behind it has plenty: resto carried 51 movements from\n-- before a movement had to say which branch it happened in.\n--\n-- The answer is already in the data. A movement happened at a shelf, and the\n-- shelf belongs to a branch — so the movement's unit is the location's, derived\n-- rather than guessed. Only the rows with no location at all fall back to the\n-- tenant's headquarters, which is where stock with no stated place has always\n-- implicitly been.\n--\n-- Additive and idempotent: it fills NULLs and never overwrites a unit that is\n-- already set.\nDO $$\nBEGIN\n IF to_regclass('public.plg_inventory_stock_movements') IS NOT NULL THEN\n UPDATE public.plg_inventory_stock_movements m\n SET unit_id = l.unit_id\n FROM public.plg_inventory_stock_locations l\n WHERE m.unit_id IS NULL AND l.id = m.stock_location_id AND l.unit_id IS NOT NULL;\n\n UPDATE public.plg_inventory_stock_movements m\n SET unit_id = u.id\n FROM app.units u\n WHERE m.unit_id IS NULL AND u.tenant_id = m.tenant_id AND u.kind = 'hq';\n END IF;\n\n IF to_regclass('public.plg_inventory_stock_positions') IS NOT NULL THEN\n UPDATE public.plg_inventory_stock_positions p\n SET unit_id = l.unit_id\n FROM public.plg_inventory_stock_locations l\n WHERE p.unit_id IS NULL AND l.id = p.stock_location_id AND l.unit_id IS NOT NULL;\n\n UPDATE public.plg_inventory_stock_positions p\n SET unit_id = u.id\n FROM app.units u\n WHERE p.unit_id IS NULL AND u.tenant_id = p.tenant_id AND u.kind = 'hq';\n END IF;\n\n IF to_regclass('public.plg_inventory_reservations') IS NOT NULL THEN\n UPDATE public.plg_inventory_reservations r\n SET unit_id = u.id\n FROM app.units u\n WHERE r.unit_id IS NULL AND u.tenant_id = r.tenant_id AND u.kind = 'hq';\n END IF;\n\n IF to_regclass('public.plg_inventory_stock_locations') IS NOT NULL THEN\n UPDATE public.plg_inventory_stock_locations l\n SET unit_id = u.id\n FROM app.units u\n WHERE l.unit_id IS NULL AND u.tenant_id = l.tenant_id AND u.kind = 'hq';\n END IF;\nEND $$;\n\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY[\n 'plg_inventory_stock_locations','plg_inventory_stock_movements',\n 'plg_inventory_stock_positions','plg_inventory_reservations'] LOOP\n CONTINUE WHEN to_regclass('public.' || t) IS NULL;\n PERFORM app.scaffold_scope(('public.' || t)::regclass, 'unit', true);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_019_THE_STOCK_MIRROR_ASKS_FIRST = `-- ============================================================================\n-- 019 — o espelho de estoque pergunta antes de escrever\n--\n-- Metade da arbitragem que a spine/146 declarou. A outra metade é do shop.\n--\n-- O 014 escreve \\`products.stock = Σ posições\\` sempre que uma posição muda, e o\n-- 0009 da loja escreve \\`products.stock = inventory_count\\` sempre que um produto\n-- é salvo. Nenhum dos dois sabe do outro, então quem dispara por último ganha —\n-- a #143 da Fase 0, e o motivo de restaurant estar 20 unidades fora e salon 29.\n--\n-- Aqui o espelho passa a perguntar. Onde o inventory é o dono — que é o padrão,\n-- porque é o contrato que o 012 declarou — nada muda: mesma consulta, mesmo\n-- resultado, mesma linha escrita. Onde a loja é quem mantém o número, este\n-- espelho se cala em vez de disputar.\n--\n-- A OMISSÃO É O PONTO. Um saldo derivado que sobrescreve o saldo de outro livro\n-- não é um espelho, é uma corrida — e o lado que perde não deixa rastro.\n-- ============================================================================\n\nCREATE OR REPLACE FUNCTION app.inventory_refresh_product_stock(p_tenant uuid, p_product uuid)\nRETURNS void LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n -- A pergunta nova. Sem registro a resposta é 'inventory', então toda pool que\n -- não declarou nada continua exatamente como estava.\n IF app.product_stock_owner(p_tenant) <> 'inventory' THEN\n RETURN;\n END IF;\n\n -- Guarda original: a coluna ainda existe? Assim uma decisão futura do catálogo\n -- de derrubá-la não custa nada aqui.\n IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'products' AND column_name = 'stock') THEN\n EXECUTE 'UPDATE public.products p SET stock = s.qty FROM (SELECT coalesce(sum(quantity), 0) AS qty FROM public.plg_inventory_stock_positions x WHERE x.tenant_id = $1 AND x.product_id = $2) s WHERE p.id = $2 AND p.tenant_id = $1 AND p.stock IS DISTINCT FROM s.qty'\n USING p_tenant, p_product;\n END IF;\nEND $$;\n\nREVOKE ALL ON FUNCTION app.inventory_refresh_product_stock(uuid, uuid) FROM public, anon, authenticated;\n\n-- min_stock não entra: ele vem de plg_inventory_product_settings e a loja não\n-- tem opinião sobre mínimo. Um escritor só desde sempre, e continua.\n`\n\nexport const MIGRATION_020_STOCK_REACTS_TO_A_COMPLETED_SALE = `-- ---------------------------------------------------------------------------\n-- 020_stock_reacts_to_a_completed_sale.sql — the first real wiring of the event\n-- contract (#277).\n--\n-- The decision (rodada 3, Q2) made the domain-event log the contract between\n-- plugins for business effect. 149 built the consumer. This is the first thing\n-- that actually crosses the boundary through it, and it was chosen because it is\n-- the case that broke: a sale closed on the storefront at 2am moved no stock,\n-- because the only paths that ever moved it were a direct call inside\n-- \\`shop_place_order\\` and a screen someone had open.\n--\n-- WHAT IT DOES. Subscribes to \\`order.completed\\`. For each line of that Venda\n-- whose product is stock-tracked, it records a \\`sale\\` movement — which is what\n-- the position table derives the balance from, so nothing here writes a balance.\n--\n-- WHY IT CANNOT DOUBLE-COUNT, which is the only thing that matters when two\n-- books existed:\n--\n-- · 146 already registered WHO maintains a tenant's stock number\n-- (app.product_stock_owner). This handler does nothing at all for a tenant\n-- the shop owns — the shop's own decrement stays the single writer there\n-- until #276 retires it. On an inventory tenant, the handler is the writer\n-- and there is no second one.\n-- · Delivery is keyed (event, plugin, handler) by 149, so the same fact\n-- cannot be delivered twice even if the consumer runs twice.\n-- · And the movement itself carries the order id in \\`document_number\\`, so a\n-- replay that somehow got past both is still visible as one row per line\n-- rather than two silent decrements.\n--\n-- WHY IT IS NOT A TRIGGER ON orders. A trigger would run inside the writer's\n-- transaction: a stock failure would roll back the sale, and the base would\n-- depend on an optional plugin being installed. The whole point of the log is\n-- that the fact survives the reaction failing.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.plg_inventory_on_order_completed(p_event jsonb)\nRETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_tenant uuid := nullif(p_event ->> 'tenant_id', '')::uuid;\n v_order uuid := nullif(p_event ->> 'subject_id', '')::uuid;\n v_location uuid;\n v_line record;\n v_moved integer := 0;\n v_skipped integer := 0;\nBEGIN\n IF v_tenant IS NULL OR v_order IS NULL THEN\n RAISE EXCEPTION 'order.completed carried no tenant or subject id' USING ERRCODE = '22023';\n END IF;\n\n -- 146's register: on a tenant whose stock number the shop maintains, this\n -- plugin is not the writer and must not act. Silence here is the correct\n -- behaviour, and the count says so out loud.\n IF public.app_product_stock_owner(v_tenant) <> 'inventory' THEN\n RETURN jsonb_build_object('skipped', 'stock owner is not inventory for this tenant');\n END IF;\n\n -- The default location of the unit that sold, falling back to the tenant's\n -- default. A tenant with no stock location has no stock to move.\n SELECT l.id INTO v_location\n FROM public.plg_inventory_stock_locations l\n WHERE l.tenant_id = v_tenant\n ORDER BY (l.is_default IS TRUE) DESC, l.created_at\n LIMIT 1;\n\n IF v_location IS NULL THEN\n RETURN jsonb_build_object('skipped', 'tenant has no stock location');\n END IF;\n\n FOR v_line IN\n SELECT oi.product_id, oi.quantity\n FROM public.order_items oi\n JOIN public.products p ON p.id = oi.product_id\n WHERE oi.order_id = v_order\n AND oi.tenant_id = v_tenant\n AND oi.product_id IS NOT NULL\n AND coalesce(oi.quantity, 0) > 0\n AND p.kind = 'good' -- a service consumes nothing\n LOOP\n -- One movement per line. The trigger on the movements table is what applies\n -- it to the position; this never writes a balance itself.\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, quantity, movement_type, stock_location_id, document_number, reason)\n VALUES (v_tenant, v_line.product_id, v_line.quantity, 'sale', v_location, v_order::text,\n 'order.completed via the event log (#277)');\n v_moved := v_moved + 1;\n END LOOP;\n\n RETURN jsonb_build_object('movements', v_moved, 'skipped_lines', v_skipped, 'order_id', v_order);\nEND $$;\n\nCOMMENT ON FUNCTION public.plg_inventory_on_order_completed(jsonb) IS\n 'Records a sale movement per line of a completed Venda (#277). Does nothing on a tenant whose stock number the shop maintains (146) — that is what keeps one writer per book.';\n\nREVOKE ALL ON FUNCTION public.plg_inventory_on_order_completed(jsonb) FROM public, anon, authenticated;\nGRANT EXECUTE ON FUNCTION public.plg_inventory_on_order_completed(jsonb) TO service_role;\n\n-- app.product_stock_owner lives in the \\`app\\` schema, which a SECURITY DEFINER\n-- function with an empty search_path can reach only by name. This is the public\n-- wrapper the handler calls, and it exists here rather than in the base because\n-- the base has no reason to expose it.\nCREATE OR REPLACE FUNCTION public.app_product_stock_owner(p_tenant uuid)\nRETURNS text LANGUAGE sql STABLE SECURITY DEFINER SET search_path = ''\nAS $$ SELECT app.product_stock_owner(p_tenant) $$;\n\nREVOKE ALL ON FUNCTION public.app_product_stock_owner(uuid) FROM public, anon, authenticated;\nGRANT EXECUTE ON FUNCTION public.app_product_stock_owner(uuid) TO service_role;\n\n-- The subscription: a row, declared by the plugin that reacts, in the plugin's\n-- own migration. Nothing about this touches the base's tables beyond the\n-- registry the base published for exactly this.\nSELECT public.register_event_subscription(\n 'inventory',\n 'order.completed',\n 'plg_inventory_on_order_completed',\n 'A completed Venda consumes stock, one movement per line (#277)',\n 5\n);\n`\n\nexport const MIGRATION_021_THE_MOVEMENT_WRITES_THE_ARCHETYPE = `-- ---------------------------------------------------------------------------\n-- 021_the_movement_writes_the_archetype.sql — the ledger feeds the one number\n-- (#276, ADR 0024).\n--\n-- 151 made \\`public.stock_balances\\` the archetype and \\`public.stock_apply\\` its\n-- only writer. This is the inventory plugin becoming that writer: the movement\n-- it already records now also applies its delta to the archetype, so the base\n-- can answer \"how much is there\" without asking a plugin.\n--\n-- THE GRAIN TRANSLATION, which is the whole substance of this file. The plugin\n-- counts by (product, location, batch, expiry); the archetype counts by\n-- (variant, unit). So:\n--\n-- product → variant the product's DEFAULT variant. A catalogue that never\n-- created variants has one per product (144's is_default),\n-- and a movement on a product with no variant at all\n-- writes nothing rather than inventing one — it shows up\n-- in 151's reconciliation instead of as a wrong number.\n-- location → unit the location's unit, which the plugin already stores.\n-- batch, expiry stay here. They are how this plugin organises what sits\n-- in the unit, and the archetype does not need them to\n-- answer its question.\n--\n-- The plugin's own positions are unchanged: this adds a writer to the base, it\n-- does not move the plugin's book. Two books would be the thing ADR 0024\n-- forbids — but the archetype is not a second book, it is THE book, and the\n-- positions become its detail. Retiring them is the follow-up, gated on 151's\n-- reconciliation reading zero.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION app.inventory_default_variant(p_tenant uuid, p_product uuid)\nRETURNS uuid\nLANGUAGE sql STABLE SECURITY DEFINER SET search_path = ''\nAS $$\n SELECT v.id\n FROM public.product_variants v\n WHERE v.tenant_id = p_tenant\n AND v.product_id = p_product\n AND v.is_active\n ORDER BY (v.is_default IS TRUE) DESC, v.sort_order, v.created_at\n LIMIT 1\n$$;\n\n-- N15c: nothing in schema \\`app\\` is callable by anon. A function created without\n-- this is granted to PUBLIC by default, which is how a helper becomes a hole.\nREVOKE ALL ON FUNCTION app.inventory_default_variant(uuid, uuid) FROM public, anon, authenticated;\n\nCOMMENT ON FUNCTION app.inventory_default_variant(uuid, uuid) IS\n 'Which variant a product-level movement belongs to (#276): the default one, else the first active. NULL when the catalogue has none — the movement then writes no balance rather than inventing a variant.';\n\nCREATE OR REPLACE FUNCTION app.inventory_sync_archetype_balance(\n p_tenant uuid, p_product uuid, p_location uuid, p_delta numeric\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_variant uuid := app.inventory_default_variant(p_tenant, p_product);\n v_unit uuid;\nBEGIN\n IF v_variant IS NULL OR coalesce(p_delta, 0) = 0 THEN\n RETURN;\n END IF;\n SELECT l.unit_id INTO v_unit\n FROM public.plg_inventory_stock_locations l\n WHERE l.id = p_location AND l.tenant_id = p_tenant;\n\n PERFORM public.stock_apply(p_tenant, v_variant, v_unit, p_delta, 0, 'inventory');\nEND $$;\n\nREVOKE ALL ON FUNCTION app.inventory_sync_archetype_balance(uuid, uuid, uuid, numeric) FROM public, anon, authenticated;\n\nCOMMENT ON FUNCTION app.inventory_sync_archetype_balance(uuid, uuid, uuid, numeric) IS\n 'Applies a movement''s delta to public.stock_balances at the archetype''s grain (#276). Batch and expiry stay with this plugin; the archetype gets the number.';\n\n-- The trigger 014 already installed, with the archetype write added. Everything\n-- else about it is unchanged, deliberately: this file is a writer being added,\n-- not a rewrite of the position engine.\nCREATE OR REPLACE FUNCTION app.inventory_movements_after_insert()\nRETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_prev text := coalesce(current_setting('fayz.inventory_internal', true), 'off');\n r record;\nBEGIN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.source_location_id, NEW.batch_number, NEW.expiration_date,\n NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n PERFORM app.inventory_sync_archetype_balance(NEW.tenant_id, NEW.product_id, NEW.source_location_id, NEW.quantity);\n\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.destination_location_id, NEW.batch_number, NEW.expiration_date,\n -NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n PERFORM app.inventory_sync_archetype_balance(NEW.tenant_id, NEW.product_id, NEW.destination_location_id, -NEW.quantity);\n END IF;\n\n PERFORM app.inventory_refresh_product_stock(NEW.tenant_id, NEW.product_id);\n PERFORM set_config('fayz.inventory_internal', v_prev, true);\n RETURN NULL;\nEND $$;\n\n-- Backfill: every position this plugin already holds, summed to the archetype's\n-- grain. Guarded so a replay adds nothing — the archetype row is SET to the\n-- position total rather than incremented by it.\nDO $$\nDECLARE\n r record;\nBEGIN\n FOR r IN\n SELECT p.tenant_id,\n app.inventory_default_variant(p.tenant_id, p.product_id) AS variant_id,\n l.unit_id,\n sum(p.quantity) AS on_hand\n FROM public.plg_inventory_stock_positions p\n LEFT JOIN public.plg_inventory_stock_locations l ON l.id = p.stock_location_id\n GROUP BY p.tenant_id, app.inventory_default_variant(p.tenant_id, p.product_id), l.unit_id\n LOOP\n CONTINUE WHEN r.variant_id IS NULL;\n INSERT INTO public.stock_balances (tenant_id, variant_id, unit_id, on_hand, updated_by)\n VALUES (r.tenant_id, r.variant_id, r.unit_id, r.on_hand, 'inventory:backfill')\n ON CONFLICT (tenant_id, variant_id, coalesce(unit_id, '00000000-0000-0000-0000-000000000000'::uuid)) DO UPDATE\n SET on_hand = EXCLUDED.on_hand, updated_by = 'inventory:backfill', updated_at = now();\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_022_THE_COUNT_TABLES_JOIN_THE_TEMPLATE = `-- ---------------------------------------------------------------------------\n-- 022_the_count_tables_join_the_template.sql — two tables that carry tenant_id\n-- and were never given row security (#283).\n--\n-- Found by the plugin review the same night it was written, which is the\n-- argument for having it: \\`plg_inventory_count_sessions\\` and\n-- \\`plg_inventory_count_items\\` were added by 010 and left out of 011's scaffold\n-- list. On a shared cluster — many businesses in one database — a table with\n-- tenant_id and no policy is every tenant's stock count readable by every other.\n--\n-- Nothing bespoke: the same platform template every other inventory table went\n-- through. They land ENFORCED rather than shadowed, and that is not a shortcut —\n-- shadow exists to measure a new predicate against an existing one before it\n-- starts refusing, and here there is no existing one. A rule cannot take a row\n-- away from someone who was never allowed to see it.\n-- ---------------------------------------------------------------------------\n\nDO $$\nDECLARE\n t record;\nBEGIN\n IF to_regprocedure('app.scaffold_table(regclass, text, text, boolean, text)') IS NULL THEN\n RAISE NOTICE 'plugin-inventory 022: app.scaffold_table missing — skipped';\n RETURN;\n END IF;\n\n FOR t IN SELECT * FROM (VALUES\n ('plg_inventory_count_sessions', 'inventory.count_session'),\n ('plg_inventory_count_items', 'inventory.count_item')\n ) AS v(table_name, resource_type)\n LOOP\n IF to_regclass('public.' || t.table_name) IS NULL THEN CONTINUE; END IF;\n -- 'enforce', explicitly and deterministically. Shadow exists to measure a\n -- new predicate against an existing one before it starts refusing; here\n -- there is none, so there is nothing to measure and nothing to lose.\n PERFORM app.scaffold_table(('public.' || t.table_name)::regclass, t.resource_type, 'inventory', false, 'enforce');\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t.table_name);\n EXECUTE format('GRANT ALL ON public.%I TO service_role', t.table_name);\n END LOOP;\nEND $$;\n\n-- The template is what enables row security; this is the belt to its braces, so\n-- a pool whose scaffold helper is older still gets the table locked rather than\n-- open.\nALTER TABLE public.plg_inventory_count_sessions ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_count_items ENABLE ROW LEVEL SECURITY;\n`\n\nexport const MIGRATION_023_PRODUCT_IMAGES_ARE_REGISTERED_FILES = `-- ---------------------------------------------------------------------------\n-- 023_product_images_are_registered_files.sql — product photos use the file\n-- archetype introduced by the spine in 152.\n--\n-- The bytes remain in Supabase Storage. public.documents is the canonical\n-- register that says what the file is about and where those bytes live. The\n-- legacy products.image_url remains a compatibility projection while existing\n-- readers migrate to the register.\n-- ---------------------------------------------------------------------------\n\nSELECT public.register_kind(\n 'document',\n 'inventory_product_image',\n 'inventory',\n NULL,\n NULL,\n 'A product photo managed by the inventory plugin'\n);\n\nINSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)\nVALUES (\n 'inventory-images',\n 'inventory-images',\n true,\n 8388608,\n ARRAY['image/jpeg','image/png','image/webp','image/heic','image/heif']\n)\nON CONFLICT (id) DO UPDATE SET\n public = EXCLUDED.public,\n file_size_limit = EXCLUDED.file_size_limit,\n allowed_mime_types = EXCLUDED.allowed_mime_types;\n\nDROP POLICY IF EXISTS plg_inventory_images_read ON storage.objects;\nDROP POLICY IF EXISTS plg_inventory_images_insert ON storage.objects;\nDROP POLICY IF EXISTS plg_inventory_images_update ON storage.objects;\nDROP POLICY IF EXISTS plg_inventory_images_delete ON storage.objects;\n\nCREATE POLICY plg_inventory_images_read ON storage.objects\n FOR SELECT TO anon, authenticated\n USING (bucket_id = 'inventory-images');\n\nCREATE POLICY plg_inventory_images_insert ON storage.objects\n FOR INSERT TO authenticated\n WITH CHECK (\n bucket_id = 'inventory-images'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_inventory_images_update ON storage.objects\n FOR UPDATE TO authenticated\n USING (\n bucket_id = 'inventory-images'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n )\n WITH CHECK (\n bucket_id = 'inventory-images'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_inventory_images_delete ON storage.objects\n FOR DELETE TO authenticated\n USING (\n bucket_id = 'inventory-images'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE OR REPLACE FUNCTION public.inventory_register_product_image(\n p_product uuid,\n p_storage_path text,\n p_public_url text,\n p_file_name text,\n p_file_size integer,\n p_mime_type text\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_document uuid;\n v_prefix text;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission_anywhere('inventory.edit') THEN\n RAISE EXCEPTION 'inventory: inventory.edit required to register a product image' USING ERRCODE = '42501';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.products p\n WHERE p.id = p_product AND p.tenant_id = v_tenant AND p.kind = 'good'\n ) THEN\n RAISE EXCEPTION 'inventory: product not found in this tenant' USING ERRCODE = '22023';\n END IF;\n\n v_prefix := v_tenant::text || '/products/' || p_product::text || '/';\n IF nullif(btrim(p_storage_path), '') IS NULL OR p_storage_path NOT LIKE v_prefix || '%' THEN\n RAISE EXCEPTION 'inventory: product image path is outside its tenant/product prefix' USING ERRCODE = '22023';\n END IF;\n IF nullif(btrim(p_public_url), '') IS NULL THEN\n RAISE EXCEPTION 'inventory: product image URL is required' USING ERRCODE = '22023';\n END IF;\n IF p_file_size IS NULL OR p_file_size <= 0 OR p_file_size > 8388608 THEN\n RAISE EXCEPTION 'inventory: product image must be between 1 byte and 8 MB' USING ERRCODE = '22023';\n END IF;\n IF coalesce(p_mime_type, '') <> ALL (ARRAY['image/jpeg','image/png','image/webp','image/heic','image/heif']) THEN\n RAISE EXCEPTION 'inventory: unsupported product image type' USING ERRCODE = '22023';\n END IF;\n\n UPDATE public.documents\n SET is_active = false, status = 'archived', updated_at = now()\n WHERE tenant_id = v_tenant\n AND kind = 'inventory_product_image'\n AND subject_type = 'product'\n AND subject_id = p_product\n AND is_active;\n\n INSERT INTO public.documents (\n tenant_id, kind, title, status, file_url, file_name, file_size, mime_type,\n storage_provider, storage_bucket, storage_path, subject_type, subject_id,\n metadata, created_by, updated_by\n ) VALUES (\n v_tenant, 'inventory_product_image', coalesce(nullif(btrim(p_file_name), ''), 'Product image'),\n 'active', p_public_url, p_file_name, p_file_size, p_mime_type,\n 'supabase', 'inventory-images', p_storage_path, 'product', p_product,\n jsonb_build_object('plugin', 'inventory'), auth.uid(), auth.uid()\n ) RETURNING id INTO v_document;\n\n -- Compatibility projection for readers that have not moved to documents yet.\n UPDATE public.products\n SET image_url = p_public_url, updated_at = now()\n WHERE id = p_product AND tenant_id = v_tenant;\n\n INSERT INTO public.audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (\n v_tenant, auth.uid(), 'inventory.productImage.registered', 'document', v_document::text,\n jsonb_build_object('product_id', p_product, 'storage_path', p_storage_path)\n );\n\n RETURN v_document;\nEND $$;\n\nREVOKE ALL ON FUNCTION public.inventory_register_product_image(uuid, text, text, text, integer, text)\n FROM public, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_register_product_image(uuid, text, text, text, integer, text)\n TO authenticated, service_role;\n`\n\nexport const MIGRATION_024_RESTAURANT_ORDER_STOCK_EVENTS = `-- ---------------------------------------------------------------------------\n-- 024_restaurant_order_stock_events.sql\n--\n-- The durable order event is the business-effect boundary. A completed\n-- restaurant order consumes either the active recipe behind the sold product\n-- or, when there is no recipe, the sold product itself. The path keeps the historical\n-- \\`order_item:<id>\\` key, so pools that briefly ran the browser callback cannot\n-- consume the same line twice while converging on the event log.\n--\n-- A cancelled sale never reaches \\`completed\\`, so it creates no stock movement.\n-- Post-completion returns/refunds are a different business fact and deliberately\n-- do not weaken the core order state machine, where \\`completed\\` is terminal.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION app.inventory_consume_order_item(\n p_tenant uuid,\n p_order uuid,\n p_order_item uuid,\n p_unit uuid,\n p_product uuid,\n p_quantity numeric,\n p_actor uuid DEFAULT NULL\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_key text := 'order_item:' || p_order_item::text;\n v_op record;\n v_reservation record;\n v_recipe record;\n v_requirement jsonb;\n v_requirements jsonb := '[]'::jsonb;\n v_parsed record;\n v_position record;\n v_location uuid;\n v_remaining numeric;\n v_available numeric;\n v_take numeric;\n v_reservation_cost numeric;\n v_movement uuid;\n v_line_no integer := 0;\n v_movements jsonb := '[]'::jsonb;\n v_mode text := 'direct_product';\nBEGIN\n IF p_tenant IS NULL OR p_order IS NULL OR p_order_item IS NULL OR p_product IS NULL\n OR coalesce(p_quantity, 0) <= 0 THEN\n RAISE EXCEPTION 'inventory: invalid order item consumption request' USING ERRCODE = '22023';\n END IF;\n\n -- Compatibility with the former browser bridge. If it already reserved the\n -- recipe lines, finish those exact lines instead of resolving the recipe a\n -- second time. The confirm operation key is shared by both implementations.\n IF EXISTS (\n SELECT 1 FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.idempotency_key = v_key\n ) THEN\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n p_tenant, 'confirm', v_key,\n jsonb_build_object('source', 'order.completed', 'order_id', p_order, 'actor_id', p_actor)\n );\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR v_reservation IN\n SELECT r.* FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.idempotency_key = v_key\n ORDER BY r.line_no FOR UPDATE\n LOOP\n IF v_reservation.status = 'reserved' THEN\n SELECT p.unit_cost INTO v_reservation_cost\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant\n AND p.product_id = v_reservation.product_id\n AND p.stock_location_id = v_reservation.stock_location_id\n AND coalesce(p.batch_number, '') = coalesce(v_reservation.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_reservation.expiration_date, 'infinity'::date);\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n document_number, source_item_type, source_item_id, idempotency_key,\n line_no, operation_id, user_id, metadata)\n VALUES\n (p_tenant, v_reservation.product_id, 'out', -v_reservation.quantity,\n coalesce(v_reservation_cost, 0), v_reservation.stock_location_id,\n v_reservation.batch_number, v_reservation.expiration_date,\n v_reservation.measurement_unit_id, 'consumption', p_order::text,\n 'order_item', p_order_item, v_key, v_reservation.line_no, v_op.op_id,\n p_actor, coalesce(v_reservation.metadata, '{}'::jsonb)\n || jsonb_build_object('source', 'order.completed', 'reservation_id', v_reservation.id))\n RETURNING id INTO v_movement;\n\n UPDATE public.plg_inventory_reservations r\n SET status = 'confirmed', confirmed_at = now(), confirmed_by = p_actor,\n movement_id = v_movement\n WHERE r.id = v_reservation.id AND r.status = 'reserved';\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n END IF;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n p_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm',\n 'idempotency_key', v_key, 'source_type', 'order_item',\n 'source_id', p_order_item, 'status', 'confirmed',\n 'mode', 'legacy_reservation', 'movements', v_movements),\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'actor_id', p_actor)\n );\n END IF;\n\n SELECT r.id, r.yield_quantity INTO v_recipe\n FROM public.plg_inventory_recipes r\n WHERE r.tenant_id = p_tenant\n AND r.product_id = p_product\n AND r.is_active\n ORDER BY r.updated_at DESC, r.id\n LIMIT 1;\n\n IF v_recipe.id IS NOT NULL THEN\n IF coalesce(v_recipe.yield_quantity, 0) <= 0 THEN\n RAISE EXCEPTION 'inventory: recipe % has an invalid yield quantity', v_recipe.id\n USING ERRCODE = '22023';\n END IF;\n\n SELECT coalesce(jsonb_agg(jsonb_build_object(\n 'product_id', x.product_id,\n 'quantity', round(x.quantity * p_quantity / v_recipe.yield_quantity, 4),\n 'measurement_unit_id', x.unit_id,\n 'recipe_id', v_recipe.id\n ) ORDER BY x.first_order), '[]'::jsonb)\n INTO v_requirements\n FROM (\n SELECT i.product_id, i.unit_id, sum(i.quantity) AS quantity,\n min(i.display_order) AS first_order\n FROM public.plg_inventory_recipe_ingredients i\n WHERE i.tenant_id = p_tenant AND i.recipe_id = v_recipe.id\n GROUP BY i.product_id, i.unit_id\n ) x;\n\n IF jsonb_array_length(v_requirements) = 0 THEN\n RAISE EXCEPTION 'inventory: recipe % has no ingredients', v_recipe.id\n USING ERRCODE = '22023';\n END IF;\n v_mode := 'recipe';\n ELSE\n v_requirements := jsonb_build_array(jsonb_build_object(\n 'product_id', p_product,\n 'quantity', round(p_quantity, 4),\n 'measurement_unit_id', NULL\n ));\n END IF;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n p_tenant, 'confirm', v_key,\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'product_id', p_product,\n 'quantity', p_quantity, 'mode', v_mode, 'actor_id', p_actor)\n );\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR v_requirement IN SELECT value FROM jsonb_array_elements(v_requirements)\n LOOP\n SELECT * INTO v_parsed FROM app.inventory_parse_line(\n p_tenant,\n jsonb_strip_nulls(jsonb_build_object(\n 'product_id', v_requirement ->> 'product_id',\n 'quantity', v_requirement ->> 'quantity',\n 'measurement_unit_id', v_requirement ->> 'measurement_unit_id'\n )),\n 'positive'\n );\n\n v_remaining := round(v_parsed.quantity, 4);\n IF v_remaining <= 0 THEN\n RAISE EXCEPTION 'inventory: order item % produced a zero stock requirement', p_order_item\n USING ERRCODE = '22023';\n END IF;\n\n v_location := NULL;\n SELECT candidate.location_id INTO v_location\n FROM (\n SELECT s.default_location_id AS location_id,\n CASE WHEN p_unit IS NOT NULL AND s.unit_id = p_unit THEN 1 ELSE 2 END AS priority\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = p_tenant\n AND s.product_id = v_parsed.product_id\n AND s.default_location_id IS NOT NULL\n AND (s.unit_id IS NULL OR s.unit_id = p_unit)\n UNION ALL\n SELECT d.default_location_id, 3\n FROM public.plg_inventory_product_details d\n WHERE d.tenant_id = p_tenant\n AND d.product_id = v_parsed.product_id\n AND d.default_location_id IS NOT NULL\n UNION ALL\n SELECT l.id, 4\n FROM public.plg_inventory_stock_locations l\n WHERE l.tenant_id = p_tenant AND l.is_active\n ) candidate\n JOIN public.plg_inventory_stock_locations l\n ON l.id = candidate.location_id\n AND l.tenant_id = p_tenant\n AND l.is_active\n WHERE p_unit IS NULL OR l.unit_id = p_unit\n ORDER BY candidate.priority, l.created_at, l.id\n LIMIT 1;\n\n IF v_location IS NULL THEN\n RAISE EXCEPTION 'inventory: product % has no active stock location for order unit %',\n v_parsed.product_id, p_unit USING ERRCODE = '22023';\n END IF;\n\n FOR v_position IN\n SELECT p.*\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant\n AND p.product_id = v_parsed.product_id\n AND p.stock_location_id = v_location\n AND p.quantity > 0\n ORDER BY p.expiration_date NULLS LAST, p.created_at, p.id\n FOR UPDATE\n LOOP\n v_available := app.inventory_available(\n p_tenant, v_position.product_id, v_position.stock_location_id,\n v_position.batch_number, v_position.expiration_date\n );\n CONTINUE WHEN v_available <= 0;\n v_take := least(v_remaining, v_available);\n v_line_no := v_line_no + 1;\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n document_number, source_item_type, source_item_id, idempotency_key,\n line_no, operation_id, user_id, metadata)\n VALUES\n (p_tenant, v_parsed.product_id, 'out', -v_take,\n coalesce(v_position.unit_cost, 0), v_location,\n v_position.batch_number, v_position.expiration_date,\n coalesce(v_position.measurement_unit_id, v_parsed.measurement_unit_id),\n 'consumption', p_order::text, 'order_item', p_order_item, v_key,\n v_line_no, v_op.op_id, p_actor,\n jsonb_strip_nulls(jsonb_build_object(\n 'source', 'order.completed',\n 'mode', v_mode,\n 'recipe_id', v_requirement ->> 'recipe_id',\n 'declared', v_parsed.declared\n )))\n RETURNING id INTO v_movement;\n\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n v_remaining := round(v_remaining - v_take, 4);\n EXIT WHEN v_remaining <= 0;\n END LOOP;\n\n IF v_remaining > 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock for product % at location % (% missing)',\n v_parsed.product_id, v_location, v_remaining USING ERRCODE = '23514';\n END IF;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n p_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm',\n 'idempotency_key', v_key, 'source_type', 'order_item',\n 'source_id', p_order_item, 'status', 'confirmed', 'mode', v_mode,\n 'recipe_id', v_recipe.id, 'movements', v_movements),\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'actor_id', p_actor,\n 'movement_count', v_line_no, 'mode', v_mode)\n );\nEND $$;\n\nREVOKE ALL ON FUNCTION app.inventory_consume_order_item(uuid, uuid, uuid, uuid, uuid, numeric, uuid)\n FROM public, anon, authenticated;\n\nCREATE OR REPLACE FUNCTION public.plg_inventory_on_order_completed(p_event jsonb)\nRETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $$\nDECLARE\n v_tenant uuid := nullif(p_event ->> 'tenant_id', '')::uuid;\n v_order uuid := nullif(p_event ->> 'subject_id', '')::uuid;\n v_actor uuid := nullif(p_event ->> 'actor_id', '')::uuid;\n v_order_row record;\n v_item record;\n v_result jsonb;\n v_results jsonb := '[]'::jsonb;\n v_count integer := 0;\nBEGIN\n IF v_tenant IS NULL OR v_order IS NULL THEN\n RAISE EXCEPTION 'order.completed carried no tenant or subject id' USING ERRCODE = '22023';\n END IF;\n IF public.app_product_stock_owner(v_tenant) <> 'inventory' THEN\n RETURN jsonb_build_object('skipped', 'stock owner is not inventory for this tenant');\n END IF;\n\n SELECT o.status, o.unit_id INTO v_order_row\n FROM public.orders o WHERE o.id = v_order AND o.tenant_id = v_tenant;\n IF v_order_row.status IS NULL THEN\n RAISE EXCEPTION 'inventory: order % was not found for tenant %', v_order, v_tenant\n USING ERRCODE = '22023';\n END IF;\n IF v_order_row.status <> 'completed' THEN\n RETURN jsonb_build_object('skipped', 'order is no longer completed',\n 'order_id', v_order, 'current_status', v_order_row.status);\n END IF;\n\n FOR v_item IN\n SELECT oi.id, oi.product_id, oi.quantity\n FROM public.order_items oi\n JOIN public.products p ON p.id = oi.product_id AND p.tenant_id = v_tenant\n WHERE oi.order_id = v_order AND oi.tenant_id = v_tenant\n AND oi.product_id IS NOT NULL AND coalesce(oi.quantity, 0) > 0\n AND p.kind = 'good'\n ORDER BY oi.sort_order, oi.created_at, oi.id\n LOOP\n v_result := app.inventory_consume_order_item(\n v_tenant, v_order, v_item.id, v_order_row.unit_id,\n v_item.product_id, v_item.quantity, v_actor\n );\n v_results := v_results || v_result;\n v_count := v_count + 1;\n END LOOP;\n\n RETURN jsonb_build_object('order_id', v_order, 'consumed_items', v_count,\n 'results', v_results);\nEND $$;\n\nCOMMENT ON FUNCTION public.plg_inventory_on_order_completed(jsonb) IS\n 'Consumes a completed restaurant order from the durable event log. Active recipes expand into ingredients; products without recipes consume their own stock. The order-item key is compatible with the retired browser bridge.';\n\nREVOKE ALL ON FUNCTION public.plg_inventory_on_order_completed(jsonb)\n FROM public, anon, authenticated;\nGRANT EXECUTE ON FUNCTION public.plg_inventory_on_order_completed(jsonb) TO service_role;\n\nSELECT public.register_event_subscription(\n 'inventory', 'order.completed', 'plg_inventory_on_order_completed',\n 'A completed restaurant order consumes its active recipe or the sold product', 5\n);\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_plg_rename\", sql: MIGRATION_000_PLG_RENAME },\n { id: \"001_inventory_base\", sql: MIGRATION_001_INVENTORY_BASE },\n { id: \"002_recipes\", sql: MIGRATION_002_RECIPES },\n { id: \"003_measurement_units\", sql: MIGRATION_003_MEASUREMENT_UNITS },\n { id: \"004_stock_movement_view\", sql: MIGRATION_004_STOCK_MOVEMENT_VIEW },\n { id: \"005_product_details\", sql: MIGRATION_005_PRODUCT_DETAILS },\n { id: \"006_stock_position_slots\", sql: MIGRATION_006_STOCK_POSITION_SLOTS },\n { id: \"007_recipe_groups\", sql: MIGRATION_007_RECIPE_GROUPS },\n { id: \"008_rls_policies\", sql: MIGRATION_008_RLS_POLICIES },\n { id: \"009_agent_rpcs\", sql: MIGRATION_009_AGENT_RPCS },\n { id: \"010_stock_counts\", sql: MIGRATION_010_STOCK_COUNTS },\n { id: \"011_scaffold\", sql: MIGRATION_011_SCAFFOLD },\n { id: \"012_inventory_core_contract\", sql: MIGRATION_012_INVENTORY_CORE_CONTRACT },\n { id: \"013_inventory_units\", sql: MIGRATION_013_INVENTORY_UNITS },\n { id: \"014_inventory_positions_and_views\", sql: MIGRATION_014_INVENTORY_POSITIONS_AND_VIEWS },\n { id: \"015_inventory_rpcs\", sql: MIGRATION_015_INVENTORY_RPCS },\n { id: \"016_inventory_legacy_backfill\", sql: MIGRATION_016_INVENTORY_LEGACY_BACKFILL },\n { id: \"017_reservation_one_per_source\", sql: MIGRATION_017_RESERVATION_ONE_PER_SOURCE },\n { id: \"018_scope_locality\", sql: MIGRATION_018_SCOPE_LOCALITY },\n { id: \"019_the_stock_mirror_asks_first\", sql: MIGRATION_019_THE_STOCK_MIRROR_ASKS_FIRST },\n { id: \"020_stock_reacts_to_a_completed_sale\", sql: MIGRATION_020_STOCK_REACTS_TO_A_COMPLETED_SALE },\n { id: \"021_the_movement_writes_the_archetype\", sql: MIGRATION_021_THE_MOVEMENT_WRITES_THE_ARCHETYPE },\n { id: \"022_the_count_tables_join_the_template\", sql: MIGRATION_022_THE_COUNT_TABLES_JOIN_THE_TEMPLATE },\n { id: \"023_product_images_are_registered_files\", sql: MIGRATION_023_PRODUCT_IMAGES_ARE_REGISTERED_FILES },\n { id: \"024_restaurant_order_stock_events\", sql: MIGRATION_024_RESTAURANT_ORDER_STOCK_EVENTS },\n]\n","import React from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { InventoryPage } from './views/InventoryPage'\nimport { createInventoryDashboardWidgets } from './views/dashboardWidgets'\nimport type { ResolvedInventoryConfig } from './context'\nimport type { InventoryDataProvider } from './data/types'\nimport { createMockInventoryProvider } from './data/mock'\nimport { createSupabaseInventoryProvider } from './data/supabase'\nimport { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'\nimport { PluginSettingsPanel } from '@fayz-ai/admin'\nimport { createInventoryStore } from './store'\nimport { inventoryRegistries } from './data/registries'\nimport { inventoryLocales } from './locales'\nimport { InventoryGeneralSettings } from './components/InventoryGeneralSettings'\nimport { upsertRecipeTool } from './lib/agent-tools'\nimport { MIGRATIONS } from './migrations'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface InventoryPluginLabels {\n pageTitle: string\n pageSubtitle: string\n dashboard: string\n products: string\n productsNew: string\n productsList: string\n stock: string\n stockEntry: string\n stockExit: string\n stockHistory: string\n recipes: string\n recipesNew: string\n recipesList: string\n}\n\nexport interface InventoryPluginOptions {\n modules?: {\n recipes?: boolean\n stockLocations?: boolean\n batchTracking?: boolean\n /**\n * The product catalogue screens (list + form). Defaults on. Turn OFF when the\n * host already owns product registration elsewhere — an e-commerce app\n * manages products in the shop plugin, and two competing product CRUDs is\n * how the same product ends up entered twice, differently.\n * Stock entry/exit/history stay available either way.\n */\n products?: boolean\n }\n labels?: Partial<InventoryPluginLabels>\n productTypes?: Array<{ value: string; label: string }>\n currency?: { code?: string; locale?: string; symbol?: string }\n navPosition?: number\n navSection?: 'main' | 'secondary'\n scope?: PluginScope\n verticalId?: VerticalId\n dataProvider?: InventoryDataProvider\n locations?: Array<{ id: string; name: string; isHQ?: boolean }>\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: InventoryPluginLabels = {\n pageTitle: 'Inventory',\n pageSubtitle: 'Product catalog and stock management',\n dashboard: 'Dashboard',\n products: 'Products',\n productsNew: 'New',\n productsList: 'List',\n stock: 'Stock',\n stockEntry: 'Entry',\n stockExit: 'Exit',\n stockHistory: 'History',\n recipes: 'Recipes',\n recipesNew: 'New',\n recipesList: 'List',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\nconst DEFAULT_PRODUCT_TYPES = [\n { value: 'ingredient', label: 'Ingredient' },\n { value: 'sale', label: 'For Sale' },\n { value: 'intermediate', label: 'Intermediate' },\n { value: 'asset', label: 'Asset' },\n]\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(options?: InventoryPluginOptions): ResolvedInventoryConfig {\n return {\n modules: {\n products: options?.modules?.products !== false,\n recipes: options?.modules?.recipes !== false,\n stockLocations: options?.modules?.stockLocations !== false,\n batchTracking: options?.modules?.batchTracking ?? false,\n },\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n productTypes: options?.productTypes ?? DEFAULT_PRODUCT_TYPES,\n locations: options?.locations ?? [],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createInventoryPlugin(options?: InventoryPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n registerTranslations(inventoryLocales)\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseInventoryProvider(),\n () => createMockInventoryProvider(),\n )\n const store = createInventoryStore(provider)\n const dashboardWidgets = createInventoryDashboardWidgets({ config, provider, store })\n\n const PageComponent: React.FC<any> = () =>\n React.createElement(InventoryPage, { config, provider, store, registries: inventoryRegistries })\n\n return {\n id: 'inventory',\n defaultAgentRole: 'operations',\n name: config.labels.pageTitle,\n icon: 'Package',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n // The parts a plan can permit separately (#281, ADR 0025). Counting what\n // you have is the plugin; costing it and forecasting it are what a growing\n // operation pays for.\n facets: [\n { id: 'stock', label: 'Estoque', description: 'Saldo, movimentos e contagem.', includedWithPlugin: true },\n { id: 'costing', label: 'Custo médio e margem', description: 'Custo móvel por lote e a margem que sai dele.' },\n { id: 'purchasing', label: 'Compras e reposição', description: 'Ponto de pedido, sugestão de compra e recebimento.' },\n ],\n dependencies: [],\n // Business effects cross plugin boundaries through the durable event log.\n // Completion consumes the active recipe (or the sold product itself).\n // Cancelled sales never complete, so the app never coordinates a stock effect.\n subscribesTo: [\n {\n event: 'order.completed',\n handler: 'plg_inventory_on_order_completed',\n description: 'A completed Venda consumes its active recipe or the sold product',\n maxAttempts: 5,\n },\n ],\n // The plugin owns ALL of its SQL and says so: what installing it provisions\n // is this list, byte-for-byte the files under src/migrations (embed barrel).\n // Loose SQL was the standing contract violation (DECISIONS 2026-07-06).\n migrations: MIGRATIONS.map((m) => ({\n id: `inventory-${m.id}`,\n version: '1.0.0',\n sql: m.sql,\n description: m.id,\n })),\n declaredFeatures: [\n { id: 'inventory', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ...(config.modules.recipes ? [{ id: 'inventory.recipes', label: config.labels.recipes ?? 'Recipes', group: config.labels.pageTitle }] : []),\n ],\n queryEntities: [\n {\n key: 'inventory:products',\n writable: true,\n entity: {\n name: 'Product',\n namePlural: 'Products',\n icon: 'Package',\n limitKey: 'products',\n permission: { feature: 'inventory', action: 'read' },\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, searchable: true },\n { key: 'kind', label: 'Kind (sale/ingredient/asset)', type: 'text' },\n { key: 'price', label: 'Price', type: 'number' },\n { key: 'cost', label: 'Cost', type: 'number' },\n { key: 'sku', label: 'SKU', type: 'text', searchable: true },\n { key: 'isActive', label: 'Active', type: 'boolean' },\n { key: 'createdAt', label: 'Created at', type: 'text' },\n ],\n data: {\n table: 'products',\n tenantScoped: true,\n archetype: 'product',\n archetypeKind: 'sale',\n searchColumns: ['name', 'sku'],\n defaults: { kind: 'sale', status: 'active', is_active: true },\n },\n },\n },\n ],\n declaredLimits: [\n { key: 'products', label: 'Products', table: 'products' },\n ...(config.modules.recipes ? [{ key: 'recipes', label: config.labels.recipes ?? 'Recipes', table: 'plg_inventory_recipes' }] : []),\n ],\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 4,\n label: config.labels.pageTitle,\n route: '/inventory',\n icon: 'Package',\n permission: { feature: 'inventory', action: 'read' as const },\n },\n ],\n routes: [\n {\n path: '/inventory',\n component: PageComponent,\n permission: { feature: 'inventory', action: 'read' as const },\n // Products live on this hand-built page, not a CRUD route, so nothing\n // would register them and a product the assistant just created would\n // resolve to no page at all.\n entityRoutes: ['product:sale', 'product'],\n },\n ],\n widgets: [],\n dashboardWidgets,\n aiTools: [\n {\n id: 'inventory.low-stock',\n name: 'getLowStock',\n description: 'Lists products with stock below minimum threshold.',\n icon: 'AlertTriangle',\n mode: 'read' as const,\n category: 'Inventory',\n parameters: {\n type: 'object' as const,\n properties: {\n threshold: { type: 'number' as const, description: 'Custom stock threshold' },\n },\n },\n suggestions: [\n { label: 'Which products are running low?' },\n { label: 'What ingredients need restocking?', verticalId: 'food' as const },\n { label: 'Show me a stock summary' },\n { label: 'What are my most used products?' },\n ],\n permission: { feature: 'inventory', action: 'read' as const },\n },\n // `role: 'finance'` is on the tool itself — the plugin defaults to\n // 'operations' and cost per dish belongs to the finance colleague.\n ...(config.modules.recipes ? [upsertRecipeTool] : []),\n ],\n declaredRpcs: [\n ...(config.modules.recipes ? [{\n name: 'agent_inventory_upsert_recipe',\n kind: 'write' as const,\n description:\n 'Guarded recipe upsert: agent_guard (role→plan→recipes cap), ingredient names resolved to products.id inside SQL, unmatched ones returned and stored for the screen to recover, audited.',\n audits: true,\n }] : []),\n ],\n registries: inventoryRegistries,\n settings: [\n {\n id: 'inventory',\n label: 'Inventory',\n icon: 'Package',\n // PluginSettingsPanel, not the toggles component directly. Declaring\n // `registries` does nothing for settings on its own — the panel is the\n // only thing that turns them into screens, which is why Stock Locations,\n // Categories, Units and Suppliers all existed in code and appeared\n // nowhere. financial and crm already render through it.\n component: (() => {\n const Tab: React.FC = () => React.createElement(PluginSettingsPanel, {\n title: config.labels.pageTitle,\n generalSettings: React.createElement(InventoryGeneralSettings),\n registries: inventoryRegistries,\n hostPluginId: 'inventory',\n routeBase: '/settings/inventory',\n })\n Tab.displayName = 'InventorySettingsTab'\n return Tab\n })() as unknown as React.ComponentType<unknown>,\n order: 11,\n permission: { feature: 'inventory', action: 'read' as const },\n },\n ],\n locales: inventoryLocales,\n }\n}\n\nexport type { InventoryDataProvider } from './data/types'\nexport type { ResolvedInventoryConfig } from './context'\n\n// The movement vocabulary is exported so data importers map onto the same list\n// the UI renders, instead of keeping a private copy that drifts.\nexport {\n MOVEMENT_TYPES,\n MOVEMENT_TYPE_VALUES,\n LEGACY_PT_MOVEMENT_TYPE,\n movementTypeSpec,\n normalizeMovementType,\n} from './lib/movement-vocabulary'\nexport type { MovementTypeSpec } from './lib/movement-vocabulary'\n// O vocabulário só é reusável se o TIPO do verbo vier junto: quem mapeia\n// \"entrada\" para o razão de outro módulo precisa nomear o que recebeu.\nexport type { MovementType } from './types'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/views/DashboardView.tsx","../src/data/tables.ts","../src/lib/movement-vocabulary.ts","../src/views/ProductStockTab.tsx","../src/views/productEntity.tsx","../src/views/ProductListView.tsx","../src/views/ProductCrudForm.tsx","../src/views/ProductDetailView.tsx","../src/views/StockMovementView.tsx","../src/views/MovementHistoryView.tsx","../src/views/StockCountsView.tsx","../src/views/StockCountFormView.tsx","../src/lib/stock-count.ts","../src/views/StockCountSessionView.tsx","../src/lib/recipe-cost.ts","../src/lib/agent-tools.ts","../src/views/RecipesView.tsx","../src/views/RecipeFormView.tsx","../src/components/RecipeGapsPanel.tsx","../src/views/RecipeDetailView.tsx","../src/views/UsageAuditView.tsx","../src/components/InventoryGeneralSettings.tsx","../src/components/InventoryOnboarding.tsx","../src/views/InventoryPage.tsx","../src/views/dashboardWidgets.tsx","../src/data/mock.ts","../src/data/reference-data.ts","../src/data/supabase.ts","../src/store.ts","../src/data/registries.ts","../src/lib/setup-guides.ts","../src/lib/onboarding.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/migrations/index.ts","../src/index.ts"],"names":["jsx","t","movements","jsxs","useTranslation","products","useState","useMemo","useEffect","useCallback","toast","React","SubpageHeader","MOVEMENT_TYPES","Package","signedQuantity","ArrowDownRight","ArrowUpRight","RefreshCw","ArrowRightLeft","Trash2","Button","CrudListView","TeachMeLink","Fragment","ConfirmDialog","recipes","errorMessage","useRef","useLimitGuard","invalidateLimit","name","SearchSelect","Plus","AlertTriangle","DetailSkeleton","DataTable","CountedField","ListView","Check","ctx","nextId","applyPositionDelta","createStore","PluginSettingsPanel"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;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;AA2+G/B,IAAM,sDAAA,GAAyD,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,CAAA;AAiR/D,IAAM,uCAAA,GAA0C,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;A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","file":"index.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig } from '@fayz-ai/admin'\nimport type { InventoryPluginLabels } from './index'\nimport type { InventoryDataProvider } from './data/types'\nimport type { InventoryUIState } from './store'\n\nexport interface InventoryModules {\n /** Product catalogue screens. Off when the host registers products elsewhere. */\n products: boolean\n recipes: boolean\n stockLocations: boolean\n batchTracking: boolean\n}\n\nexport type InventoryCurrency = CurrencyConfig\n\nexport interface ProductTypeOption {\n value: string\n label: string\n}\n\nexport interface LocationOption {\n id: string\n name: string\n isHQ?: boolean\n}\n\nexport interface ResolvedInventoryConfig {\n modules: InventoryModules\n labels: InventoryPluginLabels\n currency: InventoryCurrency\n productTypes: ProductTypeOption[]\n locations: LocationOption[]\n}\n\nconst ctx = createPluginContext<ResolvedInventoryConfig, InventoryDataProvider, InventoryUIState>('InventoryPage')\n\nexport const InventoryContextProvider = ctx.ContextProvider\nexport const useInventoryConfig = ctx.useConfig\nexport const useInventoryProvider = ctx.useProvider\nexport const useInventoryStore = ctx.useStore\n\nexport { formatCurrency }\n","import React from 'react'\nimport { DashboardCanvas } from '@fayz-ai/ui'\n\n/**\n * Inventory overview. KPIs and the activity panel are registered dashboard\n * widgets (see ./dashboardWidgets), rendered through the shared DashboardCanvas;\n * the stock-value KPI also surfaces on the global app home.\n */\nexport function DashboardView() {\n return <DashboardCanvas surface=\"plugin-home\" domain=\"inventory\" showHeader={false} className=\"space-y-6\" />\n}\n","// Central physical-table-name registry for plugin-inventory.\nexport const T = {\n stockLocations: 'plg_inventory_stock_locations',\n stockMovements: 'plg_inventory_stock_movements',\n stockPositions: 'plg_inventory_stock_positions',\n recipes: 'plg_inventory_recipes',\n recipeIngredients: 'plg_inventory_recipe_ingredients',\n measurementUnits: 'plg_inventory_measurement_units',\n productCategories: 'plg_inventory_product_categories',\n productDetails: 'plg_inventory_product_details',\n recipeGroups: 'plg_inventory_recipe_groups',\n countSessions: 'plg_inventory_count_sessions',\n countItems: 'plg_inventory_count_items',\n productSettings: 'plg_inventory_product_settings',\n reservations: 'plg_inventory_reservations',\n} as const\n\n/** Slot key of plg_inventory_stock_positions — matches uq_..._slot (006). */\nexport const STOCK_POSITION_SLOT = 'tenant_id,product_id,stock_location_id,batch_number,expiration_date'\n","import type { MovementType } from '../types'\n\n/**\n * The one list of stock movement types.\n *\n * This used to be spelled out in three places — the MovementType union, the\n * form's picker and the history's icon/colour maps — which is three chances to\n * disagree. Importers make it four. Everything reads from here.\n */\nexport interface MovementTypeSpec {\n value: MovementType\n /** i18n key under the plugin's `inventory.movementType` namespace. */\n labelKey: string\n /** lucide icon name, resolved by the host's icon map. */\n icon: string\n /** Direction on stock: what the quantity does to the on-hand total. */\n effect: 'increase' | 'decrease' | 'set' | 'move'\n}\n\nexport const MOVEMENT_TYPES: readonly MovementTypeSpec[] = [\n { value: 'entry', labelKey: 'inventory.movementType.entry', icon: 'ArrowDownToLine', effect: 'increase' },\n { value: 'exit', labelKey: 'inventory.movementType.exit', icon: 'ArrowUpFromLine', effect: 'decrease' },\n { value: 'adjustment', labelKey: 'inventory.movementType.adjustment', icon: 'Scale', effect: 'set' },\n { value: 'transfer', labelKey: 'inventory.movementType.transfer', icon: 'ArrowLeftRight', effect: 'move' },\n { value: 'loss', labelKey: 'inventory.movementType.loss', icon: 'TriangleAlert', effect: 'decrease' },\n] as const\n\nexport const MOVEMENT_TYPE_VALUES: readonly MovementType[] = MOVEMENT_TYPES.map((m) => m.value)\n\nexport function movementTypeSpec(value: string): MovementTypeSpec | undefined {\n const direct = MOVEMENT_TYPES.find((m) => m.value === value)\n if (direct) return direct\n // Falls through the ledger's words too, so a row read straight from\n // `kind` still finds its label instead of rendering as `in`.\n const normalised = normalizeMovementType(value)\n return normalised ? MOVEMENT_TYPES.find((m) => m.value === normalised) : undefined\n}\n\n/**\n * Portuguese movement vocabulary used by pre-SDK apps (beautyplace and its\n * descendants). Lives next to the canonical list so a data import cannot drift\n * from what the UI can render — that is the whole reason it is here and not in\n * the importer.\n */\nexport const LEGACY_PT_MOVEMENT_TYPE: Readonly<Record<string, MovementType>> = {\n entrada: 'entry',\n saida: 'exit',\n 'saída': 'exit',\n ajuste: 'adjustment',\n transferencia: 'transfer',\n 'transferência': 'transfer',\n perda: 'loss',\n} as const\n\n/**\n * The LEDGER's own vocabulary. `plg_inventory_stock_movements.kind` is\n * in/out/transfer/adjust/reverse — a different set of words for the same five\n * ideas, fixed by a CHECK constraint. A row read back therefore says `in` where\n * the screen says `entry`, and a history that only knew the screen's words\n * printed the raw `in` as its own label.\n */\nconst LEDGER_KIND_TO_TYPE: Readonly<Record<string, MovementType>> = {\n in: 'entry',\n out: 'exit',\n transfer: 'transfer',\n adjust: 'adjustment',\n // A reversal undoes something; it is an adjustment with a reason attached.\n reverse: 'adjustment',\n}\n\n/** Normalise any known spelling to a MovementType; undefined when unrecognised. */\nexport function normalizeMovementType(raw: string): MovementType | undefined {\n const v = raw.trim().toLowerCase()\n if ((MOVEMENT_TYPE_VALUES as readonly string[]).includes(v)) return v as MovementType\n return LEDGER_KIND_TO_TYPE[v] ?? LEGACY_PT_MOVEMENT_TYPE[v]\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Plus, Undo2 } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button, ConfirmDialog, DataTable, StockEntryForm, toast } from '@fayz-ai/ui'\nimport type { StockEntrySubmit } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { Product, StockMovement, StockPosition } from '../types'\nimport { MOVEMENT_TYPES, movementTypeSpec } from '../lib/movement-vocabulary'\n\nfunction TableSkeleton() {\n return (\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-3.5 rounded bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )\n}\n\nfunction EmptyLine({ message }: { message: string }) {\n return (\n <div className=\"rounded-card border p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{message}</p>\n </div>\n )\n}\n\n/**\n * \"How much costela do I have, where, and where did it go\" — answered on the\n * product itself instead of by filtering the global ledger.\n */\nexport function ProductStockTab({ item, onChanged }: { item: Product; onChanged?: () => void }) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [positions, setPositions] = useState<StockPosition[]>([])\n const [movements, setMovements] = useState<StockMovement[]>([])\n const [loading, setLoading] = useState(true)\n const [confirming, setConfirming] = useState(false)\n const [undoing, setUndoing] = useState(false)\n const [entryVerb, setEntryVerb] = useState<string | null>(null)\n const [saving, setSaving] = useState(false)\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n const [pos, history] = await Promise.all([\n provider.getPositions(item.id),\n provider.getMovements({ productId: item.id, pageSize: 100 }),\n ])\n setPositions(pos)\n setMovements(history.data)\n } finally {\n setLoading(false)\n }\n }, [item.id, provider])\n\n useEffect(() => { void load() }, [load])\n\n /**\n * One movement, through the provider — never a direct write.\n *\n * `createMovement` is the plugin's own contract onto `inventory_receive` /\n * `inventory_adjust`: permission-checked, idempotent, and the only thing that\n * keeps the position and the shared balance in step. A form that inserted a\n * row itself would be a second writer of the book this tab is reading.\n */\n const handleEntry = useCallback(async (entry: StockEntrySubmit) => {\n setSaving(true)\n try {\n await provider.createMovement({\n productId: item.id,\n movementType: entry.verb as never,\n quantity: entry.quantity,\n ...(entry.reasonCode ? { reason: entry.reasonCode } : {}),\n ...(entry.note ? { notes: entry.note } : {}),\n ...(entry.occurredOn ? { movementDate: entry.occurredOn } : {}),\n })\n setEntryVerb(null)\n await load()\n onChanged?.()\n } catch (error) {\n toast.error(t('inventory.productDetail.movementFailed'), {\n description: (error as Error).message,\n })\n } finally {\n setSaving(false)\n }\n }, [item.id, provider, load, onChanged, t])\n\n\n // Ordered by when it was RECORDED, not by movement date: undoing means taking\n // back the last thing someone typed, which a backdated entry would hide.\n const ordered = useMemo(\n () => [...movements].sort((a, b) => (b.createdAt ?? b.movementDate).localeCompare(a.createdAt ?? a.movementDate)),\n [movements],\n )\n const lastMovement = ordered[0]\n const onHand = useMemo(() => positions.reduce((sum, p) => sum + (p.quantity ?? 0), 0), [positions])\n\n const movementLabel = (m: StockMovement) => {\n const spec = movementTypeSpec(m.movementType)\n return spec ? t(spec.labelKey) : m.movementType\n }\n\n async function handleUndo() {\n if (!lastMovement) return\n setUndoing(true)\n try {\n await provider.reverseMovement(lastMovement.id)\n toast.success(t('inventory.productDetail.undone'))\n await load()\n onChanged?.()\n } catch (err: any) {\n toast.error(t('inventory.productDetail.undoFailed'), { description: err?.message })\n } finally {\n setUndoing(false)\n setConfirming(false)\n }\n }\n\n const positionColumns: ColumnDef<StockPosition, any>[] = useMemo(() => [\n {\n accessorKey: 'stockLocationName', header: t('inventory.stock.locationLabel'),\n cell: ({ getValue }: any) => <span className=\"font-medium\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'batchNumber', header: t('inventory.stock.batchNumber'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'expirationDate', header: t('inventory.stock.expirationDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'unitCost', header: () => <span className=\"block text-right\">{t('inventory.stock.unitCostLabel')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right text-muted-foreground\">{formatCurrency(Number(getValue()) || 0, currency)}</span>,\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.stock.quantityLabel')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right font-medium tabular-nums\">{getValue() as number}</span>,\n },\n {\n id: 'total', header: () => <span className=\"block text-right\">{t('inventory.stock.totalCost')}</span>,\n cell: ({ row }: any) => (\n <span className=\"block text-right tabular-nums\">\n {formatCurrency((row.original.quantity ?? 0) * (row.original.unitCost ?? 0), currency)}\n </span>\n ),\n },\n ], [currency, t])\n\n const movementColumns: ColumnDef<StockMovement, any>[] = useMemo(() => [\n {\n accessorKey: 'movementDate', header: t('inventory.history.columnDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{getValue() as string}</span>,\n },\n {\n accessorKey: 'movementType', header: t('inventory.history.columnType'),\n cell: ({ row }: any) => <span className=\"text-xs\">{movementLabel(row.original)}</span>,\n },\n {\n accessorKey: 'stockLocationName', header: t('inventory.history.columnLocation'),\n cell: ({ row }: any) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.stockLocationName ?? '—'}\n {row.original.movementType === 'transfer' && row.original.destinationLocationName && (\n <span> → {row.original.destinationLocationName}</span>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.history.columnQty')}</span>,\n cell: ({ row }: any) => (\n <span className=\"block text-right tabular-nums\">\n {/* The ledger's own sign, not a guess from the verb. A movement\n already carries its direction in `quantity` (an `out` is\n negative), and mapping the verb instead printed every `in` from\n the ledger as a minus — the history read as if a receipt had\n removed stock. */}\n {row.original.quantity > 0 ? '+' : ''}{row.original.quantity}\n </span>\n ),\n },\n {\n accessorKey: 'totalCost', header: () => <span className=\"block text-right\">{t('inventory.history.columnTotal')}</span>,\n cell: ({ getValue }: any) => <span className=\"block text-right text-muted-foreground\">{formatCurrency(Number(getValue()) || 0, currency)}</span>,\n },\n ], [currency, t])\n\n if (loading) return <TableSkeleton />\n\n return (\n <div className=\"space-y-6\">\n <section className=\"space-y-2\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.productDetail.positionsTitle')}</h3>\n <div className=\"flex items-center gap-3\">\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.productDetail.onHand')} <span className=\"font-medium text-foreground tabular-nums\">{onHand}</span>\n </p>\n {/* The tab could show a balance and not change it: entries happened\n on the global ledger screen, so \"how much do I have\" and \"I just\n received ten\" were two different places. Entrada opens chosen —\n it is the one a receiving screen is for. */}\n <Button size=\"sm\" onClick={() => setEntryVerb('entry')}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('inventory.productDetail.newMovement')}\n </Button>\n </div>\n </div>\n {positions.length === 0\n ? <EmptyLine message={t('inventory.productDetail.noPositions')} />\n : <DataTable columns={positionColumns} data={positions} variant=\"card\" />}\n </section>\n\n <section className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.productDetail.historyTitle')}</h3>\n {lastMovement && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"text-destructive hover:text-destructive\"\n onClick={() => setConfirming(true)}\n >\n <Undo2 className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('inventory.productDetail.undoLast')}\n </Button>\n )}\n </div>\n {ordered.length === 0\n ? <EmptyLine message={t('inventory.history.noMovements')} />\n : <DataTable columns={movementColumns} data={ordered} variant=\"card\" />}\n </section>\n\n {/* The same form the shop's Posições tab opens — one component in\n @fayz-ai/ui, two plugins, so the reason picker and the running balance\n cannot drift apart. Each writes through its own contract: this one\n through the inventory provider, which is the ledger that owns the\n concept. */}\n <StockEntryForm\n verb={entryVerb}\n onVerbChange={setEntryVerb}\n onClose={() => setEntryVerb(null)}\n verbs={MOVEMENT_TYPES.map((m) => ({\n value: m.value,\n label: t(m.labelKey),\n effect: m.effect,\n }))}\n available={onHand}\n saving={saving}\n onSubmit={(entry: StockEntrySubmit) => void handleEntry(entry)}\n labels={{\n title: t('inventory.productDetail.newMovement'),\n quantity: t('inventory.history.columnQty'),\n }}\n />\n\n <ConfirmDialog\n open={confirming}\n variant=\"destructive\"\n title={t('inventory.productDetail.undoTitle')}\n description={lastMovement ? t('inventory.productDetail.undoDescription', {\n type: movementLabel(lastMovement),\n quantity: String(lastMovement.quantity),\n date: lastMovement.movementDate,\n }) : undefined}\n confirmLabel={t('inventory.productDetail.undoConfirm')}\n cancelLabel={t('inventory.productForm.cancel')}\n loading={undoing}\n onConfirm={() => void handleUndo()}\n onCancel={() => setConfirming(false)}\n />\n </div>\n )\n}\n","import React from 'react'\nimport type { EntityDef, EntityImageConfig, FieldDef } from '@fayz-ai/core'\nimport { formatCurrency, type InventoryCurrency, type ProductTypeOption } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport { T } from '../data/tables'\nimport { ProductStockTab } from './ProductStockTab'\n\n// ---------------------------------------------------------------------------\n// The single source of truth for the Product entity — drives BOTH the generic\n// list (CrudListView columns + facet) and the generic form (CrudFormPage\n// sections). Persistence stays in the inventory provider/store; this only\n// describes fields, columns and layout.\n// ---------------------------------------------------------------------------\n\nconst TYPE_DESCRIPTION_KEYS: Record<string, string> = {\n ingredient: 'inventory.productForm.typeIngredient',\n sale: 'inventory.productForm.typeSale',\n intermediate: 'inventory.productForm.typeIntermediate',\n asset: 'inventory.productForm.typeAsset',\n}\n\ntype T = (key: string, params?: Record<string, string | number>) => string\n\nfunction productImage(provider: InventoryDataProvider): EntityImageConfig {\n return {\n get: (row) => row.imageUrl,\n upload: async (file, row) => {\n if (!row.id) throw new Error('Salve o produto antes de enviar a imagem.')\n if (!provider.uploadProductImage) throw new Error('Envio de imagens indisponível neste ambiente.')\n return provider.uploadProductImage(row.id, file)\n },\n accept: 'image/jpeg,image/png,image/webp,image/heic,image/heif',\n // CrudFormPage keeps this File only in form state. ProductCrudForm consumes\n // it after createProduct returns the new id; it never reaches PostgREST.\n draftField: '_imageFile',\n }\n}\n\nexport function buildProductEntity(\n t: T,\n productTypes: ProductTypeOption[],\n currency: InventoryCurrency,\n /** Called by the Stock tab after it changes stock, so the page can refetch. */\n onStockChanged?: () => void,\n /** Enables the real media slot; list-only consumers may omit it. */\n provider?: InventoryDataProvider,\n): EntityDef {\n const typeOptions = productTypes.map((pt) => ({\n label: pt.label,\n value: pt.value,\n description: TYPE_DESCRIPTION_KEYS[pt.value] ? t(TYPE_DESCRIPTION_KEYS[pt.value]) : undefined,\n }))\n const typeLabel = (v: unknown) => productTypes.find((p) => p.value === v)?.label ?? String(v ?? '')\n\n // Field order is chosen so the table columns come out as\n // Product · Type · Stock · Cost · Value while the form groups stay correct.\n const fields: FieldDef[] = [\n // — General Information (form) + Product column (table) —\n {\n key: 'name', label: t('inventory.productForm.name'), type: 'text', required: true,\n group: 'general', placeholder: t('inventory.productForm.namePlaceholder'),\n searchable: true, showInTable: true, sortable: true,\n renderCell: (_v, row: any) => (\n <div>\n <div className=\"flex items-center gap-1.5\">\n <p className={`font-medium ${row.isActive === false ? 'text-muted-foreground' : ''}`}>{row.name}</p>\n {/* Fora de linha tem de SER visível: sem esta marca, desativar um\n produto não mudava nada na tela e a ação parecia não ter feito\n nada. */}\n {row.isActive === false && (\n <span className=\"inline-flex items-center rounded-full bg-muted px-1.5 py-0.5 text-[9px] font-medium text-muted-foreground\">\n {t('inventory.productList.inactive')}\n </span>\n )}\n </div>\n {row.sku && <p className=\"text-xs text-muted-foreground\">{row.sku}</p>}\n </div>\n ),\n },\n { key: 'brand', label: t('inventory.productForm.brand'), type: 'text', group: 'general', placeholder: t('inventory.productForm.brandPlaceholder'), showInTable: false },\n { key: 'sku', label: t('inventory.productForm.sku'), type: 'text', group: 'general', placeholder: t('inventory.productForm.skuPlaceholder'), searchable: true, showInTable: false },\n { key: 'barcode', label: t('inventory.productForm.barcode'), type: 'text', group: 'general', placeholder: t('inventory.productForm.barcodePlaceholder'), searchable: true, showInTable: false },\n { key: 'description', label: t('inventory.productForm.description'), type: 'textarea', group: 'general', span: 2, placeholder: t('inventory.productForm.descriptionPlaceholder'), showInTable: false },\n\n // — Classification (form: segmented) + Type column (table: badge) —\n {\n key: 'productType', label: t('inventory.productForm.classification'), type: 'segmented',\n group: 'classification', span: 2, options: typeOptions,\n showInTable: true, sortable: false,\n renderCell: (v) => (\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium bg-muted text-muted-foreground\">\n {typeLabel(v)}\n </span>\n ),\n },\n\n // — Stock column (list only) — placed before Cost for the desired column order\n {\n key: 'currentQuantity', label: t('inventory.productList.stock'), type: 'number',\n showInForm: false, showInTable: true, sortable: true,\n renderCell: (_v, row: any) => (\n <span className={`text-right block ${row.currentQuantity <= row.minQuantity ? 'text-destructive font-medium' : ''}`}>\n {row.currentQuantity}\n </span>\n ),\n },\n\n // — Pricing (form) + Cost column (table) —\n {\n key: 'costPrice', label: t('inventory.productForm.costPrice'), type: 'currency',\n group: 'pricing', currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n showInTable: true, sortable: false,\n renderCell: (v) => <span className=\"text-right block text-muted-foreground\">{formatCurrency(Number(v) || 0, currency)}</span>,\n },\n\n // — Value column (list only): stock × cost —\n {\n key: 'value', label: t('inventory.productList.value'), type: 'number',\n showInForm: false, showInTable: true, sortable: false,\n renderCell: (_v, row: any) => (\n <span className=\"text-right block font-medium\">{formatCurrency((row.currentQuantity || 0) * (row.costPrice || 0), currency)}</span>\n ),\n },\n\n {\n key: 'salePrice', label: t('inventory.productForm.salePrice'), type: 'currency', group: 'pricing',\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n showInTable: false,\n // Ingredients and intermediate preparations are inputs, not things sold\n // directly to the customer. If it is sold, it belongs to the menu-item\n // classification and gets the commercial fields there.\n visibleWhen: (vals) => vals.productType === 'sale',\n },\n {\n key: 'margin', label: t('inventory.productForm.margin'), type: 'computed', group: 'pricing', showInTable: false,\n visibleWhen: (vals) => vals.productType === 'sale',\n compute: (vals) => {\n const cost = Number(vals.costPrice) || 0\n const sale = Number(vals.salePrice) || 0\n if (sale <= 0 || cost <= 0) return null\n const m = ((sale - cost) / cost) * 100\n return { display: `${m.toFixed(1)}%`, tone: m >= 0 ? 'positive' : 'negative' }\n },\n },\n\n // — Stock Levels (form only) —\n { key: 'minQuantity', label: t('inventory.productForm.minQuantity'), type: 'number', group: 'stock', min: 0, placeholder: '0', hint: t('inventory.productForm.minQuantityHint'), showInTable: false },\n { key: 'maxQuantity', label: t('inventory.productForm.maxQuantity'), type: 'number', group: 'stock', min: 0, placeholder: t('inventory.productForm.optional'), hint: t('inventory.productForm.maxQuantityHint'), showInTable: false },\n\n // — Organisation (form only) — the four links that used to be accepted by\n // CreateProductInput and then silently dropped; they persist in\n // plg_inventory_product_details since migration 005.\n {\n key: 'categoryId', label: t('inventory.productForm.category'), type: 'relation', group: 'organization',\n relation: { table: T.productCategories, labelField: 'name' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'measurementUnitId', label: t('inventory.productForm.measurementUnit'), type: 'relation', group: 'organization',\n relation: { table: T.measurementUnits, labelField: 'abbreviation' },\n hint: t('inventory.productForm.measurementUnitHint'),\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'supplierId', label: t('inventory.productForm.supplier'), type: 'relation', group: 'organization',\n relation: { table: 'people', labelField: 'name', filter: { kind: 'supplier' } },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'defaultLocationId', label: t('inventory.productForm.defaultLocation'), type: 'relation', group: 'organization',\n relation: { table: T.stockLocations, labelField: 'name' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n ]\n\n return {\n name: t('inventory.stock.product'),\n namePlural: t('inventory.nav.products'),\n icon: 'Package',\n displayField: 'name',\n image: provider?.uploadProductImage ? productImage(provider) : undefined,\n fields,\n fieldGroups: [\n { id: 'general', label: t('inventory.productForm.generalInfo'), columns: 2, imageSlot: true },\n { id: 'classification', label: t('inventory.productForm.classification'), description: t('inventory.productForm.classificationDesc'), columns: 1 },\n { id: 'pricing', label: t('inventory.productForm.pricing'), columns: 3 },\n { id: 'stock', label: t('inventory.productForm.stockLevels'), description: t('inventory.productForm.stockLevelsDesc'), columns: 2 },\n { id: 'organization', label: t('inventory.productForm.organization'), description: t('inventory.productForm.organizationDesc'), columns: 2 },\n ],\n facets: [{ field: 'productType', allLabel: t('crud.list.allFacet') }],\n detailTabs: [\n {\n id: 'stock',\n label: t('inventory.productDetail.stockTab'),\n icon: 'Warehouse',\n component: ProductStockTab as never,\n props: { onChanged: onStockChanged },\n },\n ],\n }\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CircleCheck, CircleSlash } from 'lucide-react'\nimport { CrudListView, usePermissionOptional, type CrudBulkAction, TeachMeLink } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport { useInventoryConfig, useInventoryProvider, useInventoryStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { Product, ProductType } from '../types'\nimport { buildProductEntity } from './productEntity'\n\n// O mesmo número que o provider assume quando ninguém pede — declarado aqui\n// porque o rodapé (\"1–50 de 340\") descreve a fatia que ESTA tela pediu, e as\n// duas pontas têm que concordar.\nconst PAGE_SIZE = 50\n\n// Product list, rendered through the generic CrudListView (header · search ·\n// facet pills · table). One shared EntityDef (buildProductEntity) drives both\n// this list and the create/edit form. Data + routing stay in the inventory\n// store / module nav.\nexport function ProductListView({ onNew, onOpen }: {\n onNew?: () => void\n /** Opens the product's own page. Editing starts there, not from the row. */\n onOpen?: (id: string) => void\n}) {\n const t = useTranslation()\n const can = usePermissionOptional()\n const provider = useInventoryProvider()\n const { currency, productTypes } = useInventoryConfig()\n const products = useInventoryStore((s) => s.products)\n const productsTotal = useInventoryStore((s) => s.productsTotal)\n const productsLoading = useInventoryStore((s) => s.productsLoading)\n const fetchProducts = useInventoryStore((s) => s.fetchProducts)\n\n const [search, setSearch] = useState('')\n const [typeFilter, setTypeFilter] = useState<string | undefined>()\n const [activeFilter, setActiveFilter] = useState<string | undefined>()\n const [page, setPage] = useState(1)\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [bulkBusy, setBulkBusy] = useState(false)\n\n // O provider SEMPRE paginou — `getProducts` recorta por `range()` e devolve o\n // `count` do conjunto inteiro. Quem não pedia página era esta tela, e sem\n // `onPageChange` o CrudListView não desenha o paginador: o rodapé dizia\n // \"1–50 de 340\" e não havia como chegar nos outros 290.\n //\n // Numa página só, a lista fica na PRIMEIRA. Isso importa numa rede com\n // catálogo grande: filtrar e continuar na página 6 mostraria um vazio que\n // parece \"nenhum resultado\" e não é.\n const query = useMemo(() => ({\n productType: typeFilter as ProductType | undefined,\n search: search || undefined,\n isActive: activeFilter === undefined ? undefined : activeFilter === 'true',\n page,\n pageSize: PAGE_SIZE,\n }), [typeFilter, search, activeFilter, page])\n\n useEffect(() => {\n let active = true\n Promise.resolve(fetchProducts(query))\n .finally(() => { if (active) setLoadedOnce(true) })\n return () => { active = false }\n }, [query])\n\n const entity = useMemo(() => buildProductEntity(t, productTypes, currency), [t, productTypes, currency])\n const facets = useMemo(() => [\n {\n field: 'productType',\n allLabel: t('crud.list.allFacet'),\n options: productTypes.map((p) => ({ value: p.value, label: p.label })),\n },\n {\n field: 'isActive',\n label: t('inventory.productList.filterStatus'),\n allLabel: t('inventory.productList.filterAllStatuses'),\n options: [\n { value: 'true', label: t('inventory.productList.filterActive') },\n { value: 'false', label: t('inventory.productList.filterInactive') },\n ],\n },\n ], [productTypes, t])\n\n // --- Bulk: turn products on and off --------------------------------------\n // There is no delete in the provider — a product with stock history cannot\n // just vanish — so \"off the shelf\" is `isActive: false`, which is reversible.\n const runBulk = useCallback(async (rows: Product[], isActive: boolean) => {\n const targets = rows.filter((p) => (p.isActive ?? true) !== isActive)\n if (targets.length === 0) {\n toast.error(t('inventory.productList.bulkNothingToDo'))\n return\n }\n setBulkBusy(true)\n let done = 0\n let failed = 0\n for (const product of targets) {\n try {\n await provider.updateProduct(product.id, { isActive })\n done++\n } catch (err: unknown) {\n failed++\n console.warn('[inventory] updateProduct failed', product.id, err)\n }\n }\n setBulkBusy(false)\n await fetchProducts(query)\n if (done > 0) toast.success(t(isActive ? 'inventory.productList.bulkActivated' : 'inventory.productList.bulkDeactivated', { count: String(done) }))\n if (failed > 0) toast.error(t('inventory.productList.bulkFailed', { count: String(failed) }))\n }, [provider, fetchProducts, query, t])\n\n const bulkActions = useMemo<CrudBulkAction<Product>[] | undefined>(() => {\n if (!can('inventory', 'edit')) return undefined\n return [\n {\n id: 'deactivate',\n label: t('inventory.productList.bulkDeactivate'),\n icon: CircleSlash,\n disabled: bulkBusy,\n onSelect: (rows) => void runBulk(rows, false),\n },\n {\n id: 'activate',\n label: t('inventory.productList.bulkActivate'),\n icon: CircleCheck,\n overflow: true,\n disabled: bulkBusy,\n onSelect: (rows) => void runBulk(rows, true),\n },\n ]\n }, [can, bulkBusy, runBulk, t])\n\n return (\n <CrudListView<Product>\n headerActions={\n <TeachMeLink\n feature=\"inventory.produtos\"\n title=\"Produtos\"\n about=\"O catálogo do estoque. O tipo de produto é a divisão primária, e o estoque mínimo é o que faz o alerta de reposição significar alguma coisa — com mínimo zero, tudo vira urgente.\"\n />\n }\n entityDef={entity}\n items={loadedOnce ? products : null}\n total={productsTotal}\n search={search}\n onSearchChange={(value) => { setPage(1); setSearch(value) }}\n searchPlaceholder={t('inventory.productList.searchPlaceholder')}\n facets={facets}\n activeFilters={{ productType: typeFilter, isActive: activeFilter }}\n onFacetChange={(field, value) => {\n setPage(1)\n if (field === 'isActive') setActiveFilter(value)\n else setTypeFilter(value)\n }}\n page={page}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n bulkActions={bulkActions}\n onNew={onNew}\n // O produto É alcançável pelo agente: o plugin o publica em\n // `queryEntities` com `writable: true`, então `createRecord` resolve o\n // alvo e a porta leva a algum lugar. Ver CrudListView.aiCreate.\n aiCreate={{\n hint: t('inventory.productList.askPlaceholder'),\n description: t('inventory.productList.aiHint'),\n intro: {\n role: 'operations',\n persona: t('inventory.productList.askPersona'),\n pitch: t('inventory.productList.askPitch'),\n description: t('inventory.productList.askDescription'),\n suggestions: [0, 1, 2].map((i) => ({ label: t(`inventory.productList.askSuggestion.${i}`) })),\n },\n }}\n addLabel={t('inventory.productList.newProduct')}\n onRowClick={(row) => onOpen?.((row as { id: string }).id)}\n feature=\"inventory\"\n />\n )\n}\n","import { errorMessage } from '@fayz-ai/core'\nimport React from 'react'\nimport { SubpageHeader, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { CrudFormPage, CrudFormSkeleton, useLimitGuard, invalidateLimit, invalidateRelationOptions } from '@fayz-ai/admin'\nimport { useInventoryConfig, useInventoryStore, useInventoryProvider } from '../context'\nimport type { ProductType } from '../types'\nimport { buildProductEntity } from './productEntity'\n\n// ---------------------------------------------------------------------------\n// Product create/edit, rendered through the generic CRUD form. The sectioned\n// layout (General Information · Classification · Pricing+Margin · Stock Levels)\n// comes from the shared buildProductEntity (segmented/computed/currency field\n// types). Persistence still flows through the inventory provider/store, so the\n// metadata-JSON column mapping is unchanged.\n// ---------------------------------------------------------------------------\n\nexport function ProductCrudForm({ editId, onSaved }: { editId?: string; onSaved?: () => void }) {\n const t = useTranslation()\n const { productTypes, currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n const createProduct = useInventoryStore((s) => s.createProduct)\n const guardProducts = useLimitGuard('products')\n const isEdit = !!editId\n\n const [initialData, setInitialData] = React.useState<Record<string, any> | null>(isEdit ? null : {})\n const [headerName, setHeaderName] = React.useState('')\n const [referenceDataReady, setReferenceDataReady] = React.useState(false)\n\n // Relation selects fetch immediately when the generic form mounts. Prepare\n // the tenant first, then clear any empty result cached by an earlier visit.\n // A provider without this optional capability keeps working unchanged.\n React.useEffect(() => {\n let cancelled = false\n ;(async () => {\n try {\n await provider.ensureReferenceData?.()\n invalidateRelationOptions()\n } catch (error) {\n // Do not turn a reference-data permission problem into a blank form;\n // the select remains usable with whatever rows could be read.\n console.warn('[inventory] Could not prepare reference data', error)\n } finally {\n if (!cancelled) setReferenceDataReady(true)\n }\n })()\n return () => { cancelled = true }\n }, [provider])\n\n // Load the existing product for edit and map it to flat form values.\n React.useEffect(() => {\n if (!editId) return\n let cancelled = false\n ;(async () => {\n const p = await provider.getProductById(editId)\n if (cancelled) return\n setHeaderName(p?.name ?? '')\n setInitialData(\n p\n ? {\n name: p.name,\n id: p.id,\n imageUrl: p.imageUrl,\n brand: p.brand ?? '',\n sku: p.sku ?? '',\n barcode: p.barcode ?? '',\n description: p.description ?? '',\n productType: p.productType,\n costPrice: p.costPrice,\n salePrice: p.salePrice ?? 0,\n minQuantity: p.minQuantity,\n maxQuantity: p.maxQuantity ?? 0,\n categoryId: p.categoryId ?? '',\n measurementUnitId: p.measurementUnitId ?? '',\n supplierId: p.supplierId ?? '',\n defaultLocationId: p.defaultLocationId ?? '',\n }\n : {},\n )\n })()\n return () => { cancelled = true }\n }, [editId])\n\n const entity = React.useMemo(\n () => buildProductEntity(t, productTypes, currency, undefined, provider),\n [t, productTypes, currency, provider],\n )\n\n async function save(values: Record<string, any>) {\n const name = String(values.name ?? '').trim()\n if (!name) { toast.error(t('common.formIncomplete')); throw new Error('name required') }\n const productType = (values.productType ?? productTypes[0]?.value) as ProductType\n const payload = {\n name,\n sku: values.sku || undefined,\n barcode: values.barcode || undefined,\n brand: values.brand || undefined,\n productType,\n costPrice: Number(values.costPrice) || 0,\n // Switching a menu item back to an input must clear the old commercial\n // price as well as hide it; otherwise reports would keep treating the\n // ingredient as sellable even though the form no longer showed why.\n salePrice: productType === 'sale' ? (Number(values.salePrice) || undefined) : 0,\n minQuantity: Number(values.minQuantity) || 0,\n maxQuantity: Number(values.maxQuantity) || undefined,\n description: values.description || undefined,\n // Always sent, even when empty: an empty string clears the link, and\n // `undefined` would leave the previous value in place on edit.\n categoryId: values.categoryId ?? '',\n measurementUnitId: values.measurementUnitId ?? '',\n supplierId: values.supplierId ?? '',\n defaultLocationId: values.defaultLocationId ?? '',\n }\n const imageFile = typeof File !== 'undefined' && values._imageFile instanceof File\n ? values._imageFile\n : undefined\n if (isEdit && editId) {\n await provider.updateProduct(editId, payload)\n if (imageFile && provider.uploadProductImage) await provider.uploadProductImage(editId, imageFile)\n } else {\n // Plan quantity guard (client-side, before the provider call). Opens the\n // global UpgradeModal and aborts when the plan's product cap is reached.\n if ((await guardProducts()) === 'blocked') return\n const created = await createProduct(payload)\n if (imageFile && provider.uploadProductImage) {\n try {\n await provider.uploadProductImage(created.id, imageFile)\n } catch (error) {\n // The product already exists. Do not leave the create form in a state\n // where a retry silently creates a duplicate; report only the media\n // failure and let the user replace the photo from edit mode.\n toast.error('Produto criado, mas a foto não foi enviada.', {\n description: errorMessage(error),\n })\n }\n }\n invalidateLimit('products')\n }\n onSaved?.()\n }\n\n const title = isEdit ? (headerName || t('inventory.productForm.editProduct')) : t('inventory.productForm.newProduct')\n const subtitle = isEdit ? undefined : t('inventory.productForm.addToCatalog')\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader title={title} subtitle={subtitle} onBack={onSaved} parentLabel={t('inventory.nav.products')} />\n {/* Enquanto o produto carrega, a forma do formulário — não o vazio. Sem\n isto a tela ficava só com o cabeçalho e uma área em branco, e o\n conteúdo aparecia de uma vez empurrando tudo. */}\n {(!initialData || !referenceDataReady) && <CrudFormSkeleton hideBreadcrumb />}\n {initialData && referenceDataReady && (\n <CrudFormPage\n entityDef={entity}\n mode={isEdit ? 'edit' : 'create'}\n initialData={initialData}\n onSubmit={save}\n onCancel={() => onSaved?.()}\n namePlural={t('inventory.nav.products')}\n hideBreadcrumb\n />\n )}\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Package } from 'lucide-react'\nimport { CrudDetailPage } from '@fayz-ai/admin'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider } from '../context'\nimport type { Product } from '../types'\nimport { buildProductEntity } from './productEntity'\n\nfunction DetailSkeleton() {\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-4\">\n <div className=\"h-20 w-20 rounded-2xl bg-muted/40 animate-pulse\" />\n <div className=\"space-y-2 flex-1\">\n <div className=\"h-6 w-56 rounded bg-muted/40 animate-pulse\" />\n <div className=\"h-3 w-32 rounded bg-muted/30 animate-pulse\" />\n </div>\n </div>\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => <div key={i} className=\"h-3.5 rounded bg-muted/30 animate-pulse\" />)}\n </div>\n </div>\n )\n}\n\n/** The product's own page — overview plus the tabs the entity declares. */\nexport function ProductDetailView({ productId, initialTab, onBack, onEdit }: {\n productId: string\n initialTab?: string\n onBack: () => void\n onEdit?: () => void\n}) {\n const t = useTranslation()\n const { currency, productTypes } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [product, setProduct] = useState<Product | null>(null)\n const [loading, setLoading] = useState(true)\n const [reloadKey, setReloadKey] = useState(0)\n\n // Handed to the Stock tab: undoing a movement changes the on-hand shown here.\n const reload = useCallback(() => setReloadKey((k) => k + 1), [])\n\n useEffect(() => {\n let active = true\n setLoading(true)\n provider.getProductById(productId)\n .then((p) => { if (active) setProduct(p) })\n .finally(() => { if (active) setLoading(false) })\n return () => { active = false }\n }, [productId, provider, reloadKey])\n\n const entity = useMemo(\n () => buildProductEntity(t, productTypes, currency, reload),\n [t, productTypes, currency, reload],\n )\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.nav.products')} onBack={onBack} />\n <DetailSkeleton />\n </div>\n )\n }\n\n if (!product) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.nav.products')} onBack={onBack} />\n <div className=\"flex flex-col items-center justify-center py-16 text-center rounded-lg border-2 border-dashed border-muted\">\n <Package className=\"h-8 w-8 text-muted-foreground/30 mb-2\" />\n <p className=\"text-sm text-muted-foreground\">{t('inventory.productDetail.notFound')}</p>\n <button onClick={onBack} className=\"text-xs text-primary hover:underline mt-1\">\n {t('inventory.productDetail.backToList')}\n </button>\n </div>\n </div>\n )\n }\n\n return (\n <CrudDetailPage\n entityDef={entity}\n item={product as unknown as Record<string, any>}\n namePlural={t('inventory.nav.products')}\n basePath=\"/inventory/products\"\n initialTab={initialTab}\n onBack={onBack}\n onEdit={onEdit}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useState, useEffect, useMemo } from 'react'\nimport { Save, Plus, ArrowUpRight, ArrowDownRight, RefreshCw, ArrowRightLeft, Trash2, Package, Check, Eye, Building2 } from 'lucide-react'\nimport { useInventoryConfig, useInventoryStore, useInventoryProvider, formatCurrency } from '../context'\nimport { cn } from '@fayz-ai/ui'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SearchSelect, type SearchSelectOption } from '@fayz-ai/ui'\nimport { DatePicker } from '@fayz-ai/ui'\nimport type { MovementType, StockMovement, StockPosition, Supplier } from '../types'\nimport { MOVEMENT_TYPE_VALUES } from '../lib/movement-vocabulary'\n\n/** O razão guarda a quantidade COM sinal; só falta o `+` explícito na entrada. */\nfunction signedQuantity(q: number | string): string {\n const n = Number(q) || 0\n return n > 0 ? `+${n}` : String(n)\n}\n\n// ---------------------------------------------------------------------------\n// Movement type config\n// ---------------------------------------------------------------------------\n\n// Presentation only. Typed as a Record so TypeScript refuses to compile if a\n// MovementType is ever added to the union and not given a card here — the array\n// this used to be would just have silently omitted it from the picker.\nconst MOVEMENT_TYPE_PRESENTATION: Record<MovementType, { labelKey: string; icon: React.ElementType; color: string; activeColor: string; descKey: string }> = {\n entry: { labelKey: 'inventory.stock.entryLabel', icon: ArrowDownRight, color: 'text-success', activeColor: 'border-success bg-success/10 text-success dark:bg-success/10', descKey: 'inventory.stock.entryDesc' },\n exit: { labelKey: 'inventory.stock.exitLabel', icon: ArrowUpRight, color: 'text-destructive', activeColor: 'border-destructive bg-destructive/10 text-destructive dark:bg-destructive/10', descKey: 'inventory.stock.exitDesc' },\n adjustment: { labelKey: 'inventory.stock.adjustmentLabel', icon: RefreshCw, color: 'text-info', activeColor: 'border-info bg-info/10 text-info dark:bg-info/10', descKey: 'inventory.stock.adjustmentDesc' },\n transfer: { labelKey: 'inventory.stock.transferLabel', icon: ArrowRightLeft, color: 'text-magic', activeColor: 'border-magic bg-magic/10 text-magic dark:bg-magic/10', descKey: 'inventory.stock.transferDesc' },\n loss: { labelKey: 'inventory.stock.lossLabel', icon: Trash2, color: 'text-warning', activeColor: 'border-warning bg-warning/10 text-warning dark:bg-warning/10', descKey: 'inventory.stock.lossDesc' },\n}\n\n// Order comes from the canonical vocabulary, so the picker and any importer\n// agree on both the set and its order.\nconst MOVEMENT_TYPES = MOVEMENT_TYPE_VALUES.map((value) => ({ value, ...MOVEMENT_TYPE_PRESENTATION[value] }))\n\n// ---------------------------------------------------------------------------\n// Movement detail card (for viewing a recorded movement)\n// ---------------------------------------------------------------------------\n\nfunction MovementDetail({ movement, currency, onClose }: {\n movement: StockMovement\n currency: { code: string; locale: string; symbol: string }\n onClose: () => void\n}) {\n const t = useTranslation()\n const typeConfig = MOVEMENT_TYPES.find((mt) => mt.value === movement.movementType)\n const TypeIcon = typeConfig?.icon ?? Package\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title={movement.productName ?? `#${movement.id.slice(0, 8)}`} onBack={onClose} parentLabel={t('inventory.nav.stock')} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n {/* Type + Product hero */}\n <div className=\"flex items-center gap-3\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-xl ${typeConfig?.activeColor ?? 'bg-muted'}`}>\n <TypeIcon className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"text-lg font-bold\">{movement.productName ?? t('inventory.stock.unknownProduct')}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">{movement.movementType} · {movement.movementDate}</p>\n </div>\n </div>\n\n {/* Key details grid */}\n <div className=\"grid gap-3 sm:grid-cols-3 pt-2 border-t\">\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.quantityLabel')}</p>\n <p className=\"text-sm font-semibold\">{signedQuantity(movement.quantity)}</p>\n </div>\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.unitCostLabel')}</p>\n <p className=\"text-sm font-semibold\">{formatCurrency(movement.unitCost, currency)}</p>\n </div>\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.totalCost')}</p>\n <p className=\"text-sm font-semibold\">{formatCurrency(movement.totalCost, currency)}</p>\n </div>\n </div>\n\n {/* Optional details */}\n <div className=\"grid gap-3 sm:grid-cols-2 pt-2 border-t\">\n {movement.stockLocationName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.locationLabel')}</p>\n <p className=\"text-sm\">{movement.stockLocationName}</p>\n </div>\n )}\n {movement.destinationLocationName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.destination')}</p>\n <p className=\"text-sm\">{movement.destinationLocationName}</p>\n </div>\n )}\n {movement.supplierName && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.supplier')}</p>\n <p className=\"text-sm\">{movement.supplierName}</p>\n </div>\n )}\n {movement.documentNumber && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.document')}</p>\n <p className=\"text-sm\">{movement.documentNumber}</p>\n </div>\n )}\n {movement.reason && (\n <div>\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.reasonLabel')}</p>\n <p className=\"text-sm\">{movement.reason}</p>\n </div>\n )}\n </div>\n\n {movement.notes && (\n <div className=\"pt-2 border-t\">\n <p className=\"text-[10px] text-muted-foreground uppercase\">{t('inventory.stock.notes')}</p>\n <p className=\"text-sm mt-0.5\">{movement.notes}</p>\n </div>\n )}\n\n <div className=\"pt-2 border-t\">\n <p className=\"text-[10px] text-muted-foreground\">{t('inventory.stock.recorded')} {new Date(movement.createdAt).toLocaleString()}</p>\n </div>\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Stock movement form\n// ---------------------------------------------------------------------------\n\nexport function StockMovementView({ defaultType, onSaved, viewMovement }: {\n defaultType: MovementType\n onSaved?: () => void\n viewMovement?: StockMovement\n}) {\n const t = useTranslation()\n const { currency, modules } = useInventoryConfig()\n const provider = useInventoryProvider()\n const products = useInventoryStore((s) => s.products)\n const locations = useInventoryStore((s) => s.locations)\n const fetchProducts = useInventoryStore((s) => s.fetchProducts)\n const fetchLocations = useInventoryStore((s) => s.fetchLocations)\n const createMovement = useInventoryStore((s) => s.createMovement)\n\n const [step, setStep] = useState(1)\n const [positions, setPositions] = useState<StockPosition[]>([])\n const [movementType, setMovementType] = useState<MovementType>(defaultType)\n const [productId, setProductId] = useState('')\n const [productLabel, setProductLabel] = useState('')\n const [quantity, setQuantity] = useState(1)\n const [unitCost, setUnitCost] = useState(0)\n const [locationId, setLocationId] = useState('')\n const [destLocationId, setDestLocationId] = useState('')\n const [reason, setReason] = useState('')\n const [documentNumber, setDocumentNumber] = useState('')\n const [notes, setNotes] = useState('')\n const [batchNumber, setBatchNumber] = useState('')\n const [expirationDate, setExpirationDate] = useState('')\n const [suppliers, setSuppliers] = useState<Supplier[]>([])\n const [supplierId, setSupplierId] = useState('')\n const [supplierLabel, setSupplierLabel] = useState('')\n const [saving, setSaving] = useState(false)\n const [savedMovement, setSavedMovement] = useState<StockMovement | null>(null)\n\n useEffect(() => { fetchProducts({}); fetchLocations() }, [])\n\n // Only an entry has a supplier — goods leaving never came from one.\n useEffect(() => {\n if (movementType !== 'entry' || suppliers.length > 0) return\n provider.getSuppliers().then(setSuppliers).catch(() => setSuppliers([]))\n }, [movementType])\n\n // Build a map of locationId → total quantity from positions.\n // NOTE: these useMemo hooks must run before the early returns below, otherwise\n // saving (which flips savedMovement) renders fewer hooks → React error.\n const positionByLocation = useMemo(() => {\n const map: Record<string, number> = {}\n for (const pos of positions) {\n if (pos.stockLocationId) {\n map[pos.stockLocationId] = (map[pos.stockLocationId] ?? 0) + pos.quantity\n }\n }\n return map\n }, [positions])\n\n // Sort locations by stock position (highest first)\n const sortedLocations = useMemo(() => {\n return [...locations].sort((a, b) => (positionByLocation[b.id] ?? 0) - (positionByLocation[a.id] ?? 0))\n }, [locations, positionByLocation])\n\n // If viewing a movement detail\n if (viewMovement) {\n return <MovementDetail movement={viewMovement} currency={currency} onClose={() => onSaved?.()} />\n }\n\n // If just saved — show success with details\n if (savedMovement) {\n return <MovementDetail movement={savedMovement} currency={currency} onClose={() => onSaved?.()} />\n }\n\n const selectedProduct = products.find((p) => p.id === productId)\n const totalCost = quantity * unitCost\n const typeConfig = MOVEMENT_TYPES.find((t) => t.value === movementType)!\n const needsReason = movementType === 'adjustment' || movementType === 'loss'\n const needsDest = movementType === 'transfer'\n\n // Product search\n function searchProducts(query: string): SearchSelectOption[] {\n const q = query.toLowerCase()\n return products\n .filter((p) => p.name.toLowerCase().includes(q) || p.sku?.toLowerCase().includes(q) || p.barcode?.includes(q))\n .slice(0, 20)\n .map((p) => ({\n id: p.id,\n label: p.name,\n subtitle: [p.sku, `${t('inventory.stock.currentStock')} ${p.currentQuantity}`].filter(Boolean).join(' · '),\n group: p.productType,\n icon: <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />,\n data: p,\n }))\n }\n\n // Auto-fill cost when product selected + fetch positions\n function handleProductSelect(id: string, option: SearchSelectOption | null) {\n setProductId(id)\n setProductLabel(option?.label ?? '')\n if (option?.data?.costPrice && unitCost === 0) {\n setUnitCost(option.data.costPrice)\n }\n // Fetch stock positions per location for this product\n if (id) {\n provider.getPositions(id).then(setPositions).catch(() => setPositions([]))\n } else {\n setPositions([])\n }\n }\n\n function searchSuppliers(query: string): SearchSelectOption[] {\n const q = query.toLowerCase()\n return suppliers\n .filter((s) => s.name.toLowerCase().includes(q) || s.documentNumber?.toLowerCase().includes(q))\n .slice(0, 20)\n .map((s) => ({\n id: s.id,\n label: s.name,\n subtitle: s.documentNumber ?? s.phone,\n icon: <Building2 className=\"h-4 w-4 text-muted-foreground shrink-0\" />,\n }))\n }\n\n const canProceedStep1 = !!productId\n const canProceedStep2 = quantity > 0 && (!needsReason || reason.trim()) && (!needsDest || destLocationId)\n const title = defaultType === 'entry' ? t('inventory.stock.entry') : defaultType === 'exit' ? t('inventory.stock.exit') : t('inventory.stock.movement')\n\n async function handleSave() {\n if (!productId || quantity <= 0) return\n setSaving(true)\n try {\n const movement = await createMovement({\n productId,\n quantity,\n movementType,\n unitCost: unitCost || undefined,\n stockLocationId: locationId || undefined,\n destinationLocationId: destLocationId || undefined,\n reason: reason || undefined,\n documentNumber: documentNumber || undefined,\n notes: notes || undefined,\n batchNumber: batchNumber || undefined,\n expirationDate: expirationDate || undefined,\n supplierId: movementType === 'entry' ? supplierId || undefined : undefined,\n })\n setSavedMovement(movement)\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={title}\n subtitle={t('inventory.stock.stepOf', { step: String(step) })}\n onBack={step > 1 ? () => setStep(step - 1) : onSaved}\n parentLabel={t('inventory.nav.stock')}\n />\n\n {/* Progress bar */}\n <div className=\"flex gap-1\">\n {[1, 2, 3].map((s) => (\n <div key={s} className={`h-1 flex-1 rounded-full transition-colors ${s <= step ? 'bg-primary' : 'bg-muted'}`} />\n ))}\n </div>\n\n {/* Step 1: What — Type + Product */}\n {step === 1 && (\n <div className=\"space-y-5\">\n {/* Movement type selector */}\n <div>\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">{t('inventory.stock.movementType')}</p>\n <div className=\"grid gap-2 sm:grid-cols-5\">\n {MOVEMENT_TYPES.map((mt) => {\n const Icon = mt.icon\n const active = movementType === mt.value\n return (\n <button\n key={mt.value}\n onClick={() => setMovementType(mt.value)}\n className={`rounded-lg border-2 p-3 text-left transition-all ${active ? mt.activeColor : 'border-transparent bg-card hover:bg-muted/30'}`}\n >\n <Icon className=\"h-4 w-4 mb-1\" />\n <p className=\"text-xs font-medium\">{t(mt.labelKey)}</p>\n <p className=\"text-[9px] text-muted-foreground mt-0.5 hidden sm:block\">{t(mt.descKey)}</p>\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Product search */}\n <SearchSelect\n value={productId}\n displayValue={productLabel}\n onChange={handleProductSelect}\n onSearch={searchProducts}\n label={t('inventory.stock.product')}\n required\n placeholder={t('inventory.stock.searchProduct')}\n minChars={1}\n debounce={150}\n renderOption={(opt) => (\n <>\n {opt.icon}\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm truncate\">{opt.label}</p>\n {opt.subtitle && <p className=\"text-[10px] text-muted-foreground\">{opt.subtitle}</p>}\n </div>\n </>\n )}\n />\n\n {selectedProduct && (\n <div className=\"rounded-lg bg-muted/30 px-4 py-3 flex items-center justify-between\">\n <div>\n <p className=\"text-sm font-medium\">{selectedProduct.name}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.stock.currentStock')} <span className=\"font-medium\">{selectedProduct.currentQuantity}</span>\n {selectedProduct.minQuantity > 0 && <> · Min: {selectedProduct.minQuantity}</>}\n {selectedProduct.costPrice > 0 && <> · Cost: {formatCurrency(selectedProduct.costPrice, currency)}</>}\n </p>\n </div>\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[9px] font-medium bg-muted text-muted-foreground capitalize\">{selectedProduct.productType}</span>\n </div>\n )}\n\n <div className=\"flex justify-end\">\n <button\n onClick={() => setStep(2)}\n disabled={!canProceedStep1}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\"\n >\n {t('inventory.stock.next')}\n </button>\n </div>\n </div>\n )}\n\n {/* Step 2: How much — Quantity + Cost + Location */}\n {step === 2 && (\n <div className=\"space-y-5\">\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.quantity')}</label>\n <input\n type=\"number\"\n min={0.01}\n step={0.01}\n value={quantity}\n onChange={(e) => setQuantity(Number(e.target.value) || 0)}\n autoFocus\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.unitCost')}</label>\n <div className=\"flex items-center mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus-within:ring-2 focus-within:ring-primary/20\">\n <span className=\"pl-2.5 text-xs text-muted-foreground\">{currency.symbol}</span>\n <input type=\"number\" min={0} step={0.01} value={unitCost} onChange={(e) => setUnitCost(Number(e.target.value) || 0)} className=\"flex-1 bg-transparent px-2 py-2 text-sm outline-none\" />\n </div>\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.total')}</label>\n <p className=\"mt-1 px-3 py-2 text-lg font-bold\">{formatCurrency(totalCost, currency)}</p>\n </div>\n </div>\n\n {/* Location — radio-style selector with stock positions */}\n {modules.stockLocations && locations.length > 0 && (\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{needsDest ? t('inventory.stock.fromLocation') : t('inventory.stock.locationLabel')}</label>\n <div className=\"flex flex-wrap gap-2 mt-1.5\">\n {sortedLocations.map((l) => {\n const qty = positionByLocation[l.id] ?? 0\n return (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => setLocationId(l.id)}\n className={cn(\n 'rounded-button border-2 px-3 py-2 text-sm font-medium transition-all flex items-center gap-2',\n locationId === l.id\n ? 'border-primary bg-primary/5 text-primary'\n : 'border-transparent bg-muted/30 text-muted-foreground hover:bg-muted/50',\n )}\n >\n <span>{l.name}</span>\n {productId && (\n <span className={cn(\n 'inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold tabular-nums',\n qty > 0\n ? 'bg-success/10 text-success'\n : 'bg-muted text-muted-foreground',\n )}>\n {qty}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n {needsDest && (\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.toLocation')}</label>\n <div className=\"flex flex-wrap gap-2 mt-1.5\">\n {sortedLocations.filter((l) => l.id !== locationId).map((l) => {\n const qty = positionByLocation[l.id] ?? 0\n return (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => setDestLocationId(l.id)}\n className={cn(\n 'rounded-button border-2 px-3 py-2 text-sm font-medium transition-all flex items-center gap-2',\n destLocationId === l.id\n ? 'border-primary bg-primary/5 text-primary'\n : 'border-transparent bg-muted/30 text-muted-foreground hover:bg-muted/50',\n )}\n >\n <span>{l.name}</span>\n {productId && (\n <span className={cn(\n 'inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-semibold tabular-nums',\n qty > 0\n ? 'bg-success/10 text-success'\n : 'bg-muted text-muted-foreground',\n )}>\n {qty}\n </span>\n )}\n </button>\n )\n })}\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Reason (required for adjustment/loss) */}\n {needsReason && (\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.reason')}</label>\n <input type=\"text\" value={reason} onChange={(e) => setReason(e.target.value)} placeholder={movementType === 'loss' ? t('inventory.stock.reasonLossPlaceholder') : t('inventory.stock.reasonAdjustPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n )}\n </div>\n\n <div className=\"flex justify-between\">\n <button onClick={() => setStep(1)} className=\"rounded-lg border px-4 py-2 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">{t('inventory.stock.back')}</button>\n <button onClick={() => setStep(3)} disabled={!canProceedStep2} className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\">{t('inventory.stock.next')}</button>\n </div>\n </div>\n )}\n\n {/* Step 3: Review + Optional details + Save */}\n {step === 3 && (\n <div className=\"space-y-5\">\n {/* Summary card */}\n <div className=\"rounded-card border bg-card shadow-sm p-5\">\n <div className=\"flex items-center gap-3 mb-4\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-xl ${typeConfig.activeColor}`}>\n <typeConfig.icon className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{productLabel}</p>\n <p className=\"text-xs text-muted-foreground capitalize\">{movementType} · {quantity} units · {formatCurrency(totalCost, currency)}</p>\n </div>\n </div>\n\n <div className=\"grid gap-2 sm:grid-cols-3 text-xs border-t pt-3\">\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.quantityLabel')}:</span> <span className=\"font-medium\">{quantity}</span></div>\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.unitCostLabel')}:</span> <span className=\"font-medium\">{formatCurrency(unitCost, currency)}</span></div>\n <div><span className=\"text-muted-foreground\">{t('inventory.stock.total')}:</span> <span className=\"font-bold\">{formatCurrency(totalCost, currency)}</span></div>\n </div>\n </div>\n\n {/* Optional details */}\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <p className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.additionalDetails')}</p>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {movementType === 'entry' && (\n <SearchSelect\n value={supplierId}\n displayValue={supplierLabel}\n onChange={(id, option) => { setSupplierId(id); setSupplierLabel(option?.label ?? '') }}\n onSearch={searchSuppliers}\n label={t('inventory.stock.supplier')}\n placeholder={t('inventory.stock.searchSupplier')}\n noResultsLabel={t('inventory.stock.noSuppliers')}\n minChars={1}\n debounce={150}\n />\n )}\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.documentNumber')}</label>\n <input type=\"text\" value={documentNumber} onChange={(e) => setDocumentNumber(e.target.value)} placeholder={t('inventory.stock.documentPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n {modules.batchTracking && (\n <>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.batchNumber')}</label>\n <input type=\"text\" value={batchNumber} onChange={(e) => setBatchNumber(e.target.value)} placeholder={t('inventory.stock.batchPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.expirationDate')}</label>\n <DatePicker value={expirationDate} onChange={setExpirationDate} className=\"mt-1\" />\n </div>\n </>\n )}\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.stock.notes')}</label>\n <textarea value={notes} onChange={(e) => setNotes(e.target.value)} rows={2} placeholder={t('inventory.stock.notesPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n </div>\n\n <div className=\"flex justify-between\">\n <button onClick={() => setStep(2)} className=\"rounded-lg border px-4 py-2 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors\">{t('inventory.stock.back')}</button>\n <button\n onClick={handleSave}\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-5 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50\"\n >\n <Check className=\"h-3.5 w-3.5\" /> {saving ? t('inventory.stock.recording') : t('inventory.stock.recordMovement')}\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import React, { useEffect, useState, useMemo } from 'react'\nimport { ArrowUpRight, ArrowDownRight, RefreshCw, ArrowRightLeft, Trash2 } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ListView, Button } from '@fayz-ai/ui'\nimport { useInventoryStore, formatCurrency, useInventoryConfig } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport type { MovementType, StockMovement } from '../types'\nimport { movementTypeSpec } from '../lib/movement-vocabulary'\n\n/** O razão guarda a quantidade COM sinal; só falta o `+` explícito na entrada. */\nfunction signedQuantity(q: number | string): string {\n const n = Number(q) || 0\n return n > 0 ? `+${n}` : String(n)\n}\n\nconst TYPE_ICONS: Record<MovementType, React.ElementType> = {\n entry: ArrowDownRight,\n exit: ArrowUpRight,\n adjustment: RefreshCw,\n transfer: ArrowRightLeft,\n loss: Trash2,\n}\n\n/** Translated label for a movement type; falls back to the raw value. */\nfunction movementTypeLabel(type: MovementType, t: (k: string) => string): string {\n const spec = movementTypeSpec(type)\n return spec ? t(spec.labelKey) : type\n}\n\nconst TYPE_COLORS: Record<MovementType, string> = {\n entry: 'text-success',\n exit: 'text-destructive',\n adjustment: 'text-info',\n transfer: 'text-magic',\n loss: 'text-warning',\n}\n\nexport function MovementHistoryView({ onViewDetail, onNew, onNewExit }: {\n onViewDetail?: (id: string) => void\n /** Record an entry. This screen is where you already are when the goods arrive. */\n onNew?: () => void\n onNewExit?: () => void\n} = {}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const movements = useInventoryStore((s) => s.movements)\n const movementsLoading = useInventoryStore((s) => s.movementsLoading)\n const fetchMovements = useInventoryStore((s) => s.fetchMovements)\n\n const [search, setSearch] = useState('')\n\n useEffect(() => { fetchMovements({ search: search || undefined }) }, [search])\n\n const columns: ColumnDef<StockMovement, any>[] = useMemo(() => [\n {\n accessorKey: 'movementDate', header: t('inventory.history.columnDate'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{getValue() as string}</span>,\n },\n {\n accessorKey: 'productName', header: t('inventory.history.columnProduct'),\n cell: ({ getValue }: any) => <span className=\"font-medium\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'movementType', header: t('inventory.history.columnType'),\n cell: ({ getValue }: any) => {\n const type = getValue() as MovementType\n const Icon = TYPE_ICONS[type] ?? RefreshCw\n const color = TYPE_COLORS[type] ?? 'text-muted-foreground'\n return (\n <span className={`inline-flex items-center gap-1 ${color}`}>\n <Icon className=\"h-3 w-3\" />\n <span className=\"text-xs\">{movementTypeLabel(type, t)}</span>\n </span>\n )\n },\n },\n {\n id: 'location', header: t('inventory.history.columnLocation'),\n cell: ({ row }: any) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.stockLocationName ?? '—'}\n {row.original.movementType === 'transfer' && row.original.destinationLocationName && (\n <span> → {row.original.destinationLocationName}</span>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'quantity', header: t('inventory.history.columnQty'),\n cell: ({ row }: any) => (\n <span className=\"text-right block\">\n {/* A quantidade JÁ vem com sinal do razão (`out` grava -3), então\n prefixar outro dava \"--3\" — e \"+\" numa entrada de -20 mentia sobre\n a direção. O número diz para onde foi; aqui só se garante o \"+\"\n explícito no que entra. */}\n {signedQuantity(row.original.quantity)}\n </span>\n ),\n },\n {\n accessorKey: 'totalCost', header: t('inventory.history.columnTotal'),\n cell: ({ getValue }: any) => (\n <span className=\"text-right block text-muted-foreground\">{formatCurrency(getValue() as number, currency)}</span>\n ),\n },\n ], [currency, t])\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title={t('inventory.history.title')} subtitle={t('inventory.history.subtitle')} />\n\n <ListView<StockMovement>\n columns={columns}\n data={movements}\n loading={movementsLoading}\n searchPlaceholder={t('inventory.history.searchPlaceholder')}\n search={search}\n onSearchChange={setSearch}\n searchDebounce={0}\n onRowClick={onViewDetail ? (row) => onViewDetail(row.id) : undefined}\n newLabel={onNew ? t('inventory.history.newEntry') : undefined}\n onNew={onNew}\n headerActions={onNewExit ? (\n <Button variant=\"outline\" size=\"sm\" onClick={onNewExit}>\n <ArrowUpRight className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('inventory.history.newExit')}\n </Button>\n ) : undefined}\n emptyMessage={t('inventory.history.noMovements')}\n emptyActionLabel={onNew ? t('inventory.history.newEntry') : undefined}\n onEmptyAction={onNew}\n />\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CrudListView, TeachMeLink } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { CountSessionStatus, StockCountSession } from '../types'\n\nconst STATUS_TONE: Record<CountSessionStatus, string> = {\n open: 'bg-muted text-muted-foreground',\n counting: 'bg-info-soft text-info-soft-foreground',\n closed: 'bg-success-soft text-success-soft-foreground',\n cancelled: 'bg-muted text-muted-foreground line-through',\n}\n\nfunction buildCountEntity(t: (key: string, params?: Record<string, string>) => string): EntityDef {\n return {\n name: t('inventory.counts.entity'),\n namePlural: t('inventory.counts.title'),\n icon: 'ClipboardList',\n displayField: 'label',\n fields: [\n {\n key: 'label', label: t('inventory.counts.colReference'), type: 'text', searchable: true,\n renderCell: (_v, row: any) => (\n <div>\n <p className=\"font-medium\">{row.label}</p>\n <p className=\"text-xs text-muted-foreground\">{row.stockLocationName ?? '—'}</p>\n </div>\n ),\n },\n {\n key: 'openedAt', label: t('inventory.counts.colOpened'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className=\"text-xs text-muted-foreground\">{row.openedAt?.slice(0, 10) ?? '—'}</span>\n ),\n },\n {\n key: 'status', label: t('inventory.counts.colStatus'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${STATUS_TONE[row.status as CountSessionStatus]}`}>\n {t(`inventory.counts.status.${row.status}`)}\n </span>\n ),\n },\n {\n key: 'progress', label: t('inventory.counts.colProgress'), type: 'text',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums text-muted-foreground\">\n {t('inventory.counts.progress', { counted: String(row.countedCount ?? 0), total: String(row.itemCount ?? 0) })}\n </span>\n ),\n },\n {\n key: 'divergentCount', label: t('inventory.counts.colDivergent'), type: 'number',\n renderCell: (_v, row: any) => (\n <span className={`block text-right tabular-nums ${row.divergentCount ? 'font-medium text-warning-soft-foreground' : 'text-muted-foreground'}`}>\n {row.divergentCount ?? 0}\n </span>\n ),\n },\n ],\n }\n}\n\n/** The counts a tenant has run — and the way into a new one. */\nexport function StockCountsView({ onNew, onOpen }: {\n onNew?: () => void\n onOpen?: (id: string) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n const [sessions, setSessions] = useState<StockCountSession[]>([])\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [search, setSearch] = useState('')\n\n const load = useCallback(async () => {\n setSessions(await provider.getCountSessions())\n setLoadedOnce(true)\n }, [provider])\n\n useEffect(() => { void load() }, [load])\n\n const rows = useMemo(() => {\n const term = search.trim().toLowerCase()\n return sessions\n .map((session) => ({\n ...session,\n label: session.reference || `${session.stockLocationName ?? ''} · ${session.openedAt.slice(0, 10)}`.trim(),\n }))\n .filter((row) => !term || row.label.toLowerCase().includes(term))\n }, [sessions, search])\n\n const entity = useMemo(() => buildCountEntity(t), [t])\n\n return (\n <CrudListView\n headerActions={\n <TeachMeLink\n feature=\"inventory.contagem\"\n title=\"Contagem de Estoque\"\n about=\"A contagem física contra o saldo do sistema. A diferença vira ajuste com rastro: sobra ou falta, com o número do inventário.\"\n />\n }\n entityDef={entity}\n items={loadedOnce ? (rows as unknown as Array<{ id: string }>) : null}\n total={rows.length}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.counts.searchPlaceholder')}\n onNew={onNew}\n addLabel={t('inventory.counts.newCount')}\n onRowClick={(row) => onOpen?.((row as { id: string }).id)}\n emptyMessage={t('inventory.counts.empty')}\n onRefresh={() => load()}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Button, SubpageHeader, Switch, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { ProductCategory, StockLocation } from '../types'\n\nconst FIELD =\n 'w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring'\n\n/** Opening a count is four decisions: where, what, blind, and what to call it. */\nexport function StockCountFormView({ onOpened, onCancel }: {\n onOpened: (sessionId: string) => void\n onCancel: () => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n const [locations, setLocations] = useState<StockLocation[]>([])\n const [categories, setCategories] = useState<ProductCategory[]>([])\n const [locationId, setLocationId] = useState('')\n const [categoryId, setCategoryId] = useState('')\n const [reference, setReference] = useState('')\n const [blind, setBlind] = useState(true)\n const [notes, setNotes] = useState('')\n const [saving, setSaving] = useState(false)\n\n useEffect(() => {\n let active = true\n void Promise.all([provider.getLocations(), provider.getCategories()]).then(([locs, cats]) => {\n if (!active) return\n setLocations(locs)\n setCategories(cats)\n if (locs.length === 1) setLocationId(locs[0].id)\n })\n return () => { active = false }\n }, [provider])\n\n async function handleOpen() {\n if (!locationId) return\n setSaving(true)\n try {\n const session = await provider.openCountSession({\n stockLocationId: locationId,\n categoryId: categoryId || undefined,\n reference: reference.trim() || undefined,\n blind,\n notes: notes.trim() || undefined,\n })\n onOpened(session.id)\n } catch (err: any) {\n toast.error(t('inventory.counts.openFailed'), { description: err?.message })\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onCancel} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4 max-w-2xl\">\n <div>\n <h2 className=\"text-sm font-semibold\">{t('inventory.counts.formTitle')}</h2>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.counts.formSubtitle')}</p>\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.location')}</label>\n <select className={FIELD} value={locationId} onChange={(e) => setLocationId(e.target.value)}>\n <option value=\"\">{t('inventory.counts.pickLocation')}</option>\n {locations.map((l) => <option key={l.id} value={l.id}>{l.name}</option>)}\n </select>\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.category')}</label>\n <select className={FIELD} value={categoryId} onChange={(e) => setCategoryId(e.target.value)}>\n <option value=\"\">{t('inventory.counts.allCategories')}</option>\n {categories.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}\n </select>\n </div>\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.reference')}</label>\n <input\n type=\"text\" className={FIELD} value={reference}\n onChange={(e) => setReference(e.target.value)}\n placeholder={t('inventory.counts.referencePlaceholder')}\n />\n </div>\n\n <div className=\"rounded-lg bg-muted/30 px-4 py-3 flex items-start justify-between gap-4\">\n <div>\n <p className=\"text-sm font-medium\">{t('inventory.counts.blind')}</p>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.counts.blindHint')}</p>\n </div>\n <Switch checked={blind} onCheckedChange={setBlind} size=\"md\" />\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.notes')}</label>\n <textarea\n className={FIELD} rows={2} value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder={t('inventory.counts.notesPlaceholder')}\n />\n </div>\n\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={onCancel}>{t('inventory.counts.cancel')}</Button>\n <Button onClick={() => void handleOpen()} disabled={!locationId || saving}>\n {saving ? t('inventory.counts.opening') : t('inventory.counts.open')}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n","import type { StockCountItem } from '../types'\n\n// ---------------------------------------------------------------------------\n// Count variance — pure arithmetic, no data access.\n//\n// The one rule everything here enforces: an UNCOUNTED line is not a line that\n// counted zero. `countedQuantity` undefined means nobody looked at the shelf,\n// so it has no variance, it is never divergent, and the close must never emit\n// an adjustment for it. Counting zero is a real answer and is stored as 0.\n// ---------------------------------------------------------------------------\n\nexport function isCounted(item: Pick<StockCountItem, 'countedQuantity'>): boolean {\n return item.countedQuantity !== undefined && item.countedQuantity !== null\n}\n\n/** counted − system, or null when the line was never counted. */\nexport function lineVariance(\n item: Pick<StockCountItem, 'systemQuantity' | 'countedQuantity'>,\n): number | null {\n if (!isCounted(item)) return null\n return (Number(item.countedQuantity) || 0) - (Number(item.systemQuantity) || 0)\n}\n\nexport function isDivergent(\n item: Pick<StockCountItem, 'systemQuantity' | 'countedQuantity'>,\n): boolean {\n const variance = lineVariance(item)\n return variance !== null && variance !== 0\n}\n\nexport interface CountSummary {\n total: number\n counted: number\n uncounted: number\n divergent: number\n /** Net units gained or lost across the divergent lines. */\n variance: number\n /** The same, valued at each line's unit cost — what the close costs. */\n varianceValue: number\n}\n\n/** Everything the summary reads. Wider than a count line on purpose: the usage\n * audit feeds its own rows through this same arithmetic. */\nexport type CountableLine = Pick<StockCountItem, 'systemQuantity' | 'countedQuantity' | 'unitCost'>\n\nexport function summarizeCount(items: CountableLine[]): CountSummary {\n let counted = 0\n let divergent = 0\n let variance = 0\n let varianceValue = 0\n for (const item of items) {\n const delta = lineVariance(item)\n if (delta === null) continue\n counted += 1\n if (delta === 0) continue\n divergent += 1\n variance += delta\n varianceValue += delta * (Number(item.unitCost) || 0)\n }\n return {\n total: items.length,\n counted,\n uncounted: items.length - counted,\n divergent,\n variance,\n varianceValue,\n }\n}\n\n/** The lines the close will act on, in the order it will act on them. */\nexport function divergentLines(items: StockCountItem[]): StockCountItem[] {\n return items.filter(isDivergent)\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Button, ConfirmDialog, SubpageHeader, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { StockCountItem, StockCountSession } from '../types'\nimport { lineVariance, summarizeCount } from '../lib/stock-count'\n\n/**\n * The counting screen — used standing up, on a phone, in a cold room. One row\n * per product, one big number field, Enter moves to the next line.\n *\n * A blind session hides the system quantity AND the per-line variance until the\n * count is closed. Showing the variance the instant a number is typed would let\n * the counter retype until it reads zero, which is the same rubber stamp blind\n * mode exists to prevent.\n */\nexport function StockCountSessionView({ sessionId, onBack }: {\n sessionId: string\n onBack: () => void\n}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [session, setSession] = useState<StockCountSession | null>(null)\n const [items, setItems] = useState<StockCountItem[]>([])\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [loading, setLoading] = useState(true)\n const [closing, setClosing] = useState(false)\n const [confirmingClose, setConfirmingClose] = useState(false)\n const [confirmingCancel, setConfirmingCancel] = useState(false)\n const inputs = useRef<Array<HTMLInputElement | null>>([])\n\n const load = useCallback(async () => {\n setLoading(true)\n try {\n const [head, lines] = await Promise.all([\n provider.getCountSession(sessionId),\n provider.getCountItems(sessionId),\n ])\n setSession(head)\n setItems(lines)\n setDrafts(Object.fromEntries(\n lines.map((l) => [l.id, l.countedQuantity === undefined ? '' : String(l.countedQuantity)]),\n ))\n } finally {\n setLoading(false)\n }\n }, [provider, sessionId])\n\n useEffect(() => { void load() }, [load])\n\n const summary = useMemo(() => summarizeCount(items), [items])\n const closed = session?.status === 'closed' || session?.status === 'cancelled'\n const hideVariance = (session?.blind ?? false) && !closed\n\n async function commit(item: StockCountItem, raw: string) {\n const trimmed = raw.trim()\n const next = trimmed === '' ? null : Number(trimmed)\n if (next !== null && !Number.isFinite(next)) return\n const current = item.countedQuantity ?? null\n if (next === current) return\n try {\n const saved = await provider.saveCountEntry(item.id, next)\n setItems((prev) => prev.map((i) => (i.id === item.id ? { ...i, ...saved } : i)))\n if (session?.status === 'open') setSession({ ...session, status: 'counting' })\n } catch (err: any) {\n toast.error(t('inventory.counts.saveFailed'), { description: err?.message })\n }\n }\n\n async function handleClose() {\n setClosing(true)\n try {\n const result = await provider.closeCountSession(\n sessionId,\n t('inventory.counts.adjustmentReason', { reference: session?.reference ?? '' }),\n )\n toast.success(\n result.alreadyClosed\n ? t('inventory.counts.alreadyClosed')\n : t('inventory.counts.closed', { count: String(result.adjustmentsCreated) }),\n )\n await load()\n } catch (err: any) {\n toast.error(t('inventory.counts.closeFailed'), { description: err?.message })\n } finally {\n setClosing(false)\n setConfirmingClose(false)\n }\n }\n\n async function handleCancel() {\n try {\n await provider.cancelCountSession(sessionId)\n toast.success(t('inventory.counts.cancelled'))\n await load()\n } catch (err: any) {\n toast.error(t('inventory.counts.cancelFailed'), { description: err?.message })\n } finally {\n setConfirmingCancel(false)\n }\n }\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n <div className=\"rounded-card border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => <div key={i} className=\"h-8 rounded bg-muted/30 animate-pulse\" />)}\n </div>\n </div>\n )\n }\n\n if (!session) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n <div className=\"rounded-card border p-8 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('inventory.counts.notFound')}</p>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader title={t('inventory.counts.title')} onBack={onBack} />\n\n <div className=\"rounded-card border bg-card shadow-sm p-4 flex flex-wrap items-center justify-between gap-4\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold truncate\">\n {session.reference || session.stockLocationName || t('inventory.counts.entity')}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {session.stockLocationName ?? '—'}\n {session.categoryName && <> · {session.categoryName}</>}\n {' '}· {t(`inventory.counts.status.${session.status}`)}\n {session.blind && <> · {t('inventory.counts.blind')}</>}\n </p>\n </div>\n <div className=\"flex items-center gap-5 text-xs\">\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.counted')}</p>\n <p className=\"font-semibold tabular-nums\">{summary.counted}/{summary.total}</p>\n </div>\n {!hideVariance && (\n <>\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.divergent')}</p>\n <p className=\"font-semibold tabular-nums\">{summary.divergent}</p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">{t('inventory.counts.varianceValue')}</p>\n <p className={`font-semibold tabular-nums ${summary.varianceValue < 0 ? 'text-destructive' : ''}`}>\n {formatCurrency(summary.varianceValue, currency)}\n </p>\n </div>\n </>\n )}\n </div>\n {!closed && (\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setConfirmingCancel(true)}>\n {t('inventory.counts.cancelCount')}\n </Button>\n <Button size=\"sm\" onClick={() => setConfirmingClose(true)}>\n {t('inventory.counts.close')}\n </Button>\n </div>\n )}\n </div>\n\n <div className=\"rounded-card border bg-card shadow-sm divide-y\">\n {items.map((item, index) => {\n const variance = lineVariance(item)\n return (\n <div key={item.id} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{item.productName ?? item.productId}</p>\n <p className=\"text-xs text-muted-foreground\">\n {item.productSku ? `${item.productSku} · ` : ''}\n {hideVariance\n ? t('inventory.counts.blindLine')\n : `${t('inventory.counts.systemQty')} ${item.systemQuantity}`}\n </p>\n </div>\n\n {!hideVariance && (\n <span className={`w-16 shrink-0 text-right text-sm tabular-nums ${\n variance === null ? 'text-muted-foreground'\n : variance === 0 ? 'text-muted-foreground'\n : variance > 0 ? 'text-success' : 'text-destructive'\n }`}>\n {variance === null ? '—' : variance > 0 ? `+${variance}` : variance}\n </span>\n )}\n\n <input\n ref={(el) => { inputs.current[index] = el }}\n type=\"number\"\n inputMode=\"decimal\"\n step=\"0.01\"\n disabled={closed}\n value={drafts[item.id] ?? ''}\n placeholder={t('inventory.counts.notCounted')}\n onChange={(e) => setDrafts((d) => ({ ...d, [item.id]: e.target.value }))}\n onBlur={() => void commit(item, drafts[item.id] ?? '')}\n onKeyDown={(e) => {\n if (e.key !== 'Enter') return\n e.preventDefault()\n inputs.current[index + 1]?.focus()\n }}\n className=\"w-28 shrink-0 rounded-input border border-input bg-card px-3 py-2.5 text-right text-base font-medium tabular-nums shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n />\n </div>\n )\n })}\n {items.length === 0 && (\n <p className=\"px-4 py-8 text-center text-xs text-muted-foreground\">{t('inventory.counts.noItems')}</p>\n )}\n </div>\n\n <ConfirmDialog\n open={confirmingClose}\n title={t('inventory.counts.closeTitle')}\n description={t('inventory.counts.closeDescription', {\n divergent: String(summary.divergent),\n uncounted: String(summary.uncounted),\n })}\n confirmLabel={t('inventory.counts.closeConfirm')}\n cancelLabel={t('inventory.counts.cancel')}\n loading={closing}\n onConfirm={() => void handleClose()}\n onCancel={() => setConfirmingClose(false)}\n />\n\n <ConfirmDialog\n open={confirmingCancel}\n variant=\"destructive\"\n title={t('inventory.counts.cancelTitle')}\n description={t('inventory.counts.cancelDescription')}\n confirmLabel={t('inventory.counts.cancelConfirm')}\n cancelLabel={t('inventory.counts.cancel')}\n onConfirm={() => void handleCancel()}\n onCancel={() => setConfirmingCancel(false)}\n />\n </div>\n )\n}\n","import type { IngredientCostBasis } from '../types'\n\n// ---------------------------------------------------------------------------\n// Recipe cost and CMV — pure arithmetic, no data access.\n//\n// THE UNIT ASSUMPTION, STATED OUT LOUD.\n//\n// The legacy implementation (beautyplace src/hooks/useRecipeCost.ts) multiplied\n// quantity × price with no conversion at all: it assumes the quantity written\n// on a recipe line is already expressed in the ingredient product's own unit.\n// We keep that assumption, because nothing in the data can contradict it — a\n// recipe line has no unit of its own that we could convert FROM.\n//\n// The one case we do better on is the one a kitchen actually hits: a product\n// bought in boxes and consumed in grams. When a product declares a purchase\n// unit distinct from the unit it is counted in, `products.cost` is the cost of\n// that purchase unit, and `conversionFactor` says how many counted units fit in\n// it — so the per-unit cost is cost ÷ factor. Without a declared purchase unit\n// the factor means nothing and we do exactly what the legacy app did.\n//\n// Artorius has purchase_unit_id NULL and conversion_factor 1 on all 43 rows, so\n// today both branches agree; the branch is the hedge, not a behaviour change.\n// ---------------------------------------------------------------------------\n\n/** Above this the dish eats the margin — the line the legacy app drew. */\nexport const CMV_ALERT_THRESHOLD = 35\n\nexport interface CostableLine {\n quantity: number\n costBasis?: IngredientCostBasis | null\n}\n\nexport interface CostedLine<T> {\n line: T\n /** Cost of one unit as the recipe counts it. */\n unitCost: number\n /** unitCost × quantity. */\n cost: number\n}\n\nexport function ingredientUnitCost(basis?: IngredientCostBasis | null): number {\n if (!basis) return 0\n const cost = Number(basis.cost) || 0\n if (!basis.purchaseUnitId) return cost\n const factor = Number(basis.conversionFactor) || 0\n return factor > 0 ? cost / factor : cost\n}\n\nexport function lineCost(line: CostableLine): number {\n return ingredientUnitCost(line.costBasis) * (Number(line.quantity) || 0)\n}\n\nexport function costLines<T extends CostableLine>(lines: T[]): CostedLine<T>[] {\n return lines.map((line) => {\n const unitCost = ingredientUnitCost(line.costBasis)\n return { line, unitCost, cost: unitCost * (Number(line.quantity) || 0) }\n })\n}\n\nexport function recipeCost(lines: CostableLine[]): number {\n return lines.reduce((sum, line) => sum + lineCost(line), 0)\n}\n\n/** Cost as a percentage of the sale price. Null when there is no price to divide by. */\nexport function cmvPercent(cost: number, salePrice?: number | null): number | null {\n const price = Number(salePrice) || 0\n if (price <= 0) return null\n return ((Number(cost) || 0) / price) * 100\n}\n\nexport function isCmvHigh(cmv: number | null | undefined): boolean {\n return typeof cmv === 'number' && cmv > CMV_ALERT_THRESHOLD\n}\n","import type { PluginAITool } from '@fayz-ai/core'\n\n/**\n * The assistant's ficha-técnica tool. A SERVER-PLANE write (a pool RPC), so it\n * works from any page and any channel and persists straight to the tenant's\n * recipes — the same pattern agenda/financial/forms use.\n *\n * `role: 'finance'` is explicit and load-bearing: the plugin's\n * `defaultAgentRole` is 'operations', and cost per dish is the finance\n * colleague's job (Selma, \"Gerente Administrativa\" in resto-saas). Without it\n * the tool would land on the operations colleague instead.\n *\n * The recipes screen publishes the ingredient CATALOGUE through\n * `useAgentSurface`, so the model sends real product ids; the RPC still\n * resolves names for whatever it names without one.\n */\n\nconst INGREDIENT_SHAPE =\n 'An ingredient line: { product_id?, name, quantity, notes? }. ' +\n 'Prefer product_id from the catalogue in the screen context; send `name` too so an ' +\n 'unmatched line can still be shown to the user. quantity is a number in the ' +\n \"ingredient's own unit — the catalogue lists that unit.\"\n\nexport const upsertRecipeTool: PluginAITool = {\n id: 'inventory.upsertRecipe',\n name: 'upsertRecipe',\n description:\n 'Creates or edits a ficha técnica (recipe) for a menu item: what it is made of, how much it yields and how it is prepared. ' +\n 'Persisted server-side, so it works from ANY page. ' +\n 'Omit recipeId to CREATE (name required); pass recipeId to EDIT. ' +\n 'Propose the WHOLE recipe in a single call — ingredients, quantities, yield and preparation together. Do NOT interview the user ingredient by ingredient. ' +\n 'Use the ingredient catalogue in the screen context to pick real product ids; name anything else in `name` and it will come back flagged for the user to pick or create. ' +\n 'The user confirms before it is saved.',\n icon: 'BookOpen',\n mode: 'persist',\n role: 'finance',\n limitKey: 'recipes',\n permission: { feature: 'inventory.recipes', action: 'create' },\n execution: { plane: 'server', kind: 'rpc', rpc: 'agent_inventory_upsert_recipe' },\n category: 'Inventory',\n suggestions: [\n { label: 'Monte a ficha técnica do cupim defumado com queijo, 400g' },\n { label: 'Quais itens do cardápio ainda não têm ficha técnica?' },\n ],\n parameters: {\n type: 'object',\n properties: {\n recipeId: { type: 'string', description: 'Existing recipe id to EDIT. Omit to create a new one.' },\n name: { type: 'string', description: 'Recipe name — required when creating.' },\n product_id: { type: 'string', description: 'Id of the product this recipe produces, from the screen context.' },\n product_name: { type: 'string', description: 'Name of the produced product, when its id is unknown. Resolved against the catalogue.' },\n description: { type: 'string', description: 'Optional short description.' },\n yield_quantity: { type: 'number', description: 'How many units one batch yields. Defaults to 1.' },\n preparation_time_minutes: { type: 'number', description: 'Preparation time in minutes.' },\n instructions: { type: 'string', description: 'Step-by-step preparation.' },\n ingredients: {\n type: 'array',\n description: `The FULL ingredient list — REPLACES every existing line. Each item: ${INGREDIENT_SHAPE}`,\n items: { type: 'object', description: INGREDIENT_SHAPE },\n },\n },\n },\n}\n\nexport const RECIPE_SURFACE_INSTRUCTIONS = [\n 'Você está na tela de FICHAS TÉCNICAS. Para montar ou editar uma ficha use a tool upsertRecipe (ela persiste no backend).',\n 'O catálogo de insumos (id, nome, unidade, custo) e os itens do cardápio sem ficha estão no JSON da tela em contexto — use os ids de lá em vez de inventar.',\n 'Proponha a ficha inteira numa única chamada: ingredientes, quantidades, rendimento e preparo juntos. Não pergunte ingrediente a ingrediente.',\n 'Insumo que não existir no catálogo: mande mesmo assim em `name` — ele volta marcado para o usuário escolher ou cadastrar.',\n].join(' ')\n","import { errorMessage } from '@fayz-ai/core'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { CrudListView, PermissionGate, QuickActionsButton, askAI, useAgentSurface, TeachMeLink } from '@fayz-ai/admin'\nimport { useDataChanged, useTranslation } from '@fayz-ai/core'\nimport type { EntityDef, PluginQuickAction } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { InventoryCurrency } from '../context'\nimport type { Product, Recipe, RecipeIngredient } from '../types'\nimport { CMV_ALERT_THRESHOLD, cmvPercent, isCmvHigh, recipeCost } from '../lib/recipe-cost'\nimport { RECIPE_SURFACE_INSTRUCTIONS } from '../lib/agent-tools'\nimport { AlertTriangle } from 'lucide-react'\n\n// ---------------------------------------------------------------------------\n// \"Which menu items still lack a ficha técnica?\" — the question this screen\n// actually answers, which is why it is driven from PRODUCTS and not from the\n// recipes that happen to exist. A sellable product with no recipe is a row too.\n// ---------------------------------------------------------------------------\n\ninterface RecipeRow {\n /** Recipe id, or `product:<id>` for a menu item with no ficha yet. */\n id: string\n recipeId?: string\n productId?: string\n productName: string\n /** Shown under the product when the ficha is named something else. */\n recipeName?: string\n ingredientCount: number\n yieldLabel: string\n prepLabel: string\n cost: number | null\n salePrice?: number\n cmv: number | null\n missing: boolean\n}\n\n/** A menu item: something the tenant sells, whether or not it is typed as such. */\nfunction isSellable(product: Product): boolean {\n return product.productType === 'sale' || (product.salePrice ?? 0) > 0\n}\n\nfunction buildRecipeEntity(t: (key: string, params?: Record<string, string>) => string, currency: InventoryCurrency): EntityDef {\n const money = (value: number | null | undefined) =>\n value == null ? '—' : formatCurrency(value, currency)\n\n return {\n name: t('inventory.recipes.entity'),\n namePlural: t('inventory.recipes.title'),\n icon: 'BookOpen',\n displayField: 'productName',\n fields: [\n {\n key: 'productName', label: t('inventory.recipes.colProduct'), type: 'text', searchable: true,\n renderCell: (_v, row: any) => (\n <div>\n <p className=\"font-medium\">{row.productName}</p>\n {row.missing\n ? <span className=\"mt-0.5 inline-flex items-center rounded-full bg-warning-soft px-2 py-0.5 text-[10px] font-medium text-warning-soft-foreground\">{t('inventory.recipes.noSheet')}</span>\n : row.recipeName && row.recipeName !== row.productName\n ? <p className=\"text-xs text-muted-foreground\">{row.recipeName}</p>\n : null}\n </div>\n ),\n },\n {\n key: 'ingredientCount', label: t('inventory.recipes.colIngredients'), type: 'number',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums\">{row.missing ? '—' : row.ingredientCount}</span>\n ),\n },\n {\n key: 'yieldLabel', label: t('inventory.recipes.colYield'), type: 'text',\n renderCell: (_v, row: any) => <span className=\"text-xs text-muted-foreground\">{row.yieldLabel || '—'}</span>,\n },\n {\n key: 'prepLabel', label: t('inventory.recipes.colPrep'), type: 'text',\n renderCell: (_v, row: any) => <span className=\"text-xs text-muted-foreground\">{row.prepLabel || '—'}</span>,\n },\n {\n key: 'cost', label: t('inventory.recipes.colCost'), type: 'currency',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums text-muted-foreground\">{money(row.cost)}</span>\n ),\n },\n {\n key: 'salePrice', label: t('inventory.recipes.colSale'), type: 'currency',\n renderCell: (_v, row: any) => (\n <span className=\"block text-right tabular-nums\">{money(row.salePrice ?? null)}</span>\n ),\n },\n {\n key: 'cmv', label: t('inventory.recipes.colCmv'), type: 'number',\n renderCell: (_v, row: any) => (\n row.cmv == null\n ? <span className=\"block text-right text-muted-foreground\">—</span>\n : <span className={`block text-right tabular-nums font-medium ${isCmvHigh(row.cmv) ? 'text-destructive' : 'text-success'}`}>\n {row.cmv.toFixed(1)}%\n </span>\n ),\n },\n ],\n }\n}\n\nexport function RecipesView({ onNew, onView, onNewForProduct }: {\n onNew?: () => void\n onView?: (id: string) => void\n /** Starts a ficha for a menu item that has none. */\n onNewForProduct?: (productId: string) => void\n}) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n\n const [recipes, setRecipes] = useState<Recipe[]>([])\n const [lines, setLines] = useState<RecipeIngredient[]>([])\n const [products, setProducts] = useState<Product[]>([])\n const [loadedOnce, setLoadedOnce] = useState(false)\n const [loadError, setLoadError] = useState('')\n const [search, setSearch] = useState('')\n\n // A menu is menu-sized; one page is the whole answer and beats a query per row.\n const load = useCallback(async (): Promise<Recipe[]> => {\n try {\n const [recipeList, allLines, productPage] = await Promise.all([\n provider.getRecipes(),\n provider.getAllRecipeIngredients(),\n provider.getProducts({ pageSize: 500 }),\n ])\n setRecipes(recipeList)\n setLines(allLines)\n setProducts(productPage.data)\n setLoadError('')\n return recipeList\n } catch (error) {\n setLoadError(errorMessage(error))\n return []\n } finally {\n setLoadedOnce(true)\n }\n }, [provider])\n\n useEffect(() => { void load() }, [load])\n\n // The assistant's write is a server-plane RPC, so nothing local knows it\n // happened — the data bus is how this screen learns, and landing on the new\n // recipe is what makes \"criar com IA\" end somewhere the user can read.\n const knownRecipeIds = useRef<Set<string>>(new Set())\n useEffect(() => { knownRecipeIds.current = new Set(recipes.map((r) => r.id)) }, [recipes])\n\n useDataChanged({}, () => {\n void (async () => {\n const before = knownRecipeIds.current\n const after = await load()\n const created = after.find((r) => !before.has(r.id))\n if (created && onView) onView(created.id)\n })()\n })\n\n const rows = useMemo<RecipeRow[]>(() => {\n const linesByRecipe = new Map<string, RecipeIngredient[]>()\n for (const line of lines) {\n const bucket = linesByRecipe.get(line.recipeId)\n if (bucket) bucket.push(line)\n else linesByRecipe.set(line.recipeId, [line])\n }\n const productById = new Map(products.map((p) => [p.id, p]))\n\n const built: RecipeRow[] = recipes.map((recipe) => {\n const own = linesByRecipe.get(recipe.id) ?? []\n const cost = recipeCost(own)\n const product = recipe.productId ? productById.get(recipe.productId) : undefined\n const salePrice = recipe.productSalePrice ?? product?.salePrice\n return {\n id: recipe.id,\n recipeId: recipe.id,\n productId: recipe.productId,\n productName: recipe.productName ?? product?.name ?? recipe.name,\n recipeName: recipe.name,\n ingredientCount: own.length || recipe.ingredientCount || 0,\n yieldLabel: recipe.yieldQuantity ? `${recipe.yieldQuantity}${recipe.yieldUnitName ? ` ${recipe.yieldUnitName}` : ''}` : '',\n prepLabel: recipe.preparationTimeMinutes != null ? `${recipe.preparationTimeMinutes} min` : '',\n cost,\n salePrice,\n cmv: cmvPercent(cost, salePrice),\n missing: false,\n } as RecipeRow\n })\n\n const covered = new Set(recipes.map((r) => r.productId).filter(Boolean) as string[])\n for (const product of products) {\n if (!isSellable(product) || covered.has(product.id)) continue\n built.push({\n id: `product:${product.id}`,\n productId: product.id,\n productName: product.name,\n ingredientCount: 0,\n yieldLabel: '',\n prepLabel: '',\n cost: null,\n salePrice: product.salePrice,\n cmv: null,\n missing: true,\n })\n }\n\n // Missing fichas first — they are the reason to open this screen.\n return built.sort((a, b) =>\n a.missing === b.missing ? a.productName.localeCompare(b.productName) : a.missing ? -1 : 1)\n }, [recipes, lines, products])\n\n const visibleRows = useMemo(() => {\n const term = search.trim().toLowerCase()\n return term ? rows.filter((r) => r.productName.toLowerCase().includes(term)) : rows\n }, [rows, search])\n\n const entity = useMemo(() => buildRecipeEntity(t, currency), [t, currency])\n\n // The model needs real ids and real costs, not a guess at the catalogue.\n const surfaceState = useRef({ rows, products })\n surfaceState.current = { rows, products }\n const surface = useMemo(() => ({\n id: 'inventory.recipes',\n pluginId: 'inventory',\n role: 'finance' as const,\n instructions: RECIPE_SURFACE_INSTRUCTIONS,\n describe: () => {\n const { rows: current, products: catalogue } = surfaceState.current\n return {\n title: 'Fichas técnicas',\n state: {\n ingredients: catalogue\n .filter((p) => !isSellable(p) || (p.costPrice ?? 0) > 0)\n .slice(0, 200)\n .map((p) => ({ id: p.id, name: p.name, unit: p.measurementUnitName, cost: p.costPrice })),\n menuItemsWithoutRecipe: current\n .filter((r) => r.missing)\n .map((r) => ({ productId: r.productId, name: r.productName, salePrice: r.salePrice })),\n recipes: current\n .filter((r) => !r.missing)\n .map((r) => ({ id: r.recipeId, product: r.productName, cost: r.cost, cmv: r.cmv })),\n cmvAlertThreshold: CMV_ALERT_THRESHOLD,\n },\n }\n },\n tools: [],\n }), [])\n useAgentSurface(surface)\n\n const createActions = useMemo<PluginQuickAction[]>(() => [\n {\n id: 'with-ai',\n label: t('assistant.askAI'),\n description: t('inventory.recipes.aiHint'),\n icon: 'WandSparkles',\n highlight: true,\n action: () => askAI({\n hint: t('inventory.recipes.askPlaceholder'),\n intro: {\n role: 'finance',\n persona: t('inventory.recipes.askPersona'),\n pitch: t('inventory.recipes.askPitch'),\n description: t('inventory.recipes.askDescription'),\n suggestions: [0, 1, 2].map((i) => ({ label: t(`inventory.recipes.askSuggestion.${i}`) })),\n },\n }),\n },\n ...(onNew ? [{\n id: 'by-hand',\n label: t('inventory.recipes.newByHand'),\n description: t('inventory.recipes.newByHandHint'),\n icon: 'SlidersHorizontal',\n action: onNew,\n } as PluginQuickAction] : []),\n ], [t, onNew])\n\n return loadError ? (\n <div className=\"flex min-h-[320px] flex-col items-center justify-center rounded-xl border-2 border-dashed border-destructive/30 bg-destructive/5 px-6 text-center\">\n <AlertTriangle className=\"mb-3 h-8 w-8 text-destructive\" />\n <p className=\"font-medium\">{t('inventory.recipes.loadFailed')}</p>\n <p className=\"mt-1 max-w-xl text-xs text-muted-foreground\">{loadError}</p>\n <button type=\"button\" onClick={() => void load()} className=\"mt-4 rounded-button border bg-card px-4 py-2 text-sm font-medium shadow-button hover:bg-muted\">\n {t('inventory.recipes.retry')}\n </button>\n </div>\n ) : (\n <CrudListView\n entityDef={entity}\n items={loadedOnce ? (visibleRows as unknown as Array<{ id: string }>) : null}\n total={visibleRows.length}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.recipes.searchPlaceholder')}\n headerActions={\n <>\n <TeachMeLink\n feature=\"inventory.receitas\"\n title=\"Receitas / Ficha Técnica\"\n about=\"O que cada item consome. É a ficha técnica que permite a venda baixar o insumo sozinha.\"\n />\n <PermissionGate feature=\"inventory\" action=\"create\">\n <QuickActionsButton variant=\"default\" label={t('inventory.recipes.newRecipe')} actions={createActions} />\n </PermissionGate>\n </>\n }\n onRowClick={(row) => {\n const target = row as unknown as RecipeRow\n if (target.missing && target.productId) onNewForProduct?.(target.productId)\n else if (target.recipeId) onView?.(target.recipeId)\n }}\n emptyMessage={t('inventory.recipes.noRecipes')}\n onRefresh={() => load().then(() => undefined)}\n feature=\"inventory\"\n />\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Plus, Trash2, GripVertical } from 'lucide-react'\nimport { useInventoryStore, useInventoryProvider } from '../context'\nimport { toast } from '@fayz-ai/ui'\nimport { SubpageHeader, useSaveBar } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SearchSelect } from '@fayz-ai/ui'\nimport { useLimitGuard, invalidateLimit } from '@fayz-ai/admin'\nimport type { CreateRecipeIngredientInput } from '../types'\n\ninterface FormIngredient {\n _id: string\n productId: string\n productName: string\n quantity: number\n unitId: string\n unitName: string\n notes: string\n}\n\nlet fid = 1\nfunction nextId() { return `ri${fid++}` }\n\nexport function RecipeFormView({ onSaved, productId: initialProductId }: {\n onSaved?: (id?: string) => void\n /** Menu item this ficha is for, when the list started it from a missing row. */\n productId?: string\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const createRecipe = useInventoryStore((s) => s.createRecipe)\n const guardRecipes = useLimitGuard('recipes')\n\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [productId, setProductId] = useState(initialProductId ?? '')\n const [productName, setProductName] = useState('')\n\n // Named by the product it produces — the ficha the row was asking for.\n useEffect(() => {\n if (!initialProductId) return\n let active = true\n void provider.getProductById(initialProductId).then((product) => {\n if (!active || !product) return\n setProductId(product.id)\n setProductName(product.name)\n setName((current) => current || product.name)\n })\n return () => { active = false }\n }, [initialProductId, provider])\n\n const [yieldQuantity, setYieldQuantity] = useState(1)\n const [prepTime, setPrepTime] = useState('')\n const [instructions, setInstructions] = useState('')\n const [ingredients, setIngredients] = useState<FormIngredient[]>([])\n const [saving, setSaving] = useState(false)\n\n function addIngredient() {\n setIngredients([...ingredients, { _id: nextId(), productId: '', productName: '', quantity: 1, unitId: '', unitName: '', notes: '' }])\n }\n\n function updateIngredient(id: string, data: Partial<FormIngredient>) {\n setIngredients(ingredients.map((ing) => ing._id === id ? { ...ing, ...data } : ing))\n }\n\n function removeIngredient(id: string) {\n setIngredients(ingredients.filter((ing) => ing._id !== id))\n }\n\n async function handleSave() {\n if (!name.trim() || !productId || ingredients.length === 0) { toast.error(t('common.formIncomplete')); return }\n // Plan quantity guard (client-side, before the provider call). Opens the\n // global UpgradeModal and aborts when the plan's recipe cap is reached.\n if ((await guardRecipes()) === 'blocked') return\n setSaving(true)\n try {\n const recipe = await createRecipe({\n name,\n description: description || undefined,\n productId,\n yieldQuantity,\n preparationTimeMinutes: prepTime ? parseInt(prepTime) : undefined,\n instructions: instructions || undefined,\n ingredients: ingredients.filter((i) => i.productId).map((i, idx) => ({\n productId: i.productId,\n quantity: i.quantity,\n unitId: i.unitId || undefined,\n displayOrder: idx,\n notes: i.notes || undefined,\n })),\n })\n invalidateLimit('recipes')\n onSaved?.(recipe.id)\n } finally { setSaving(false) }\n }\n\n const dirty = !!(name || description || productId || prepTime || instructions || ingredients.length > 0 || yieldQuantity !== 1)\n useSaveBar({\n dirty,\n saving,\n onSave: () => { void handleSave() },\n onDiscard: () => onSaved?.(),\n saveLabel: t('inventory.recipeForm.saveRecipe'),\n })\n\n async function searchProducts(query: string) {\n const result = await provider.getProducts({ search: query, pageSize: 10 })\n return result.data.map((p) => ({ id: p.id, label: p.name, subtitle: p.sku ?? p.productType, data: p }))\n }\n\n async function quickCreateProduct(name: string, type: 'ingredient' | 'sale' = 'ingredient') {\n try {\n const product = await provider.createProduct({ name, productType: type })\n toast.success(`Product \"${name}\" created`)\n return product\n } catch {\n toast.error('Failed to create product')\n return null\n }\n }\n\n return (\n <div className=\"space-y-5\">\n <SubpageHeader\n title={t('inventory.recipeForm.newRecipe')}\n subtitle={t('inventory.recipeForm.subtitle')}\n onBack={() => onSaved?.()}\n parentLabel={t('inventory.nav.recipes')}\n />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n {/* Left: Recipe details */}\n <div className=\"rounded-card border bg-card shadow-sm p-5 space-y-4\">\n <h3 className=\"text-sm font-semibold\">{t('inventory.recipeForm.recipeDetails')}</h3>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.recipeName')} *</label>\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inventory.recipeForm.recipeNamePlaceholder')} autoFocus className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.description')}</label>\n <textarea value={description} onChange={(e) => setDescription(e.target.value)} rows={2} placeholder={t('inventory.recipeForm.descriptionPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n\n <SearchSelect\n label={`${t('inventory.recipeForm.produces')} *`}\n value={productId}\n displayValue={productName}\n onChange={(id, opt) => { setProductId(id); setProductName(opt?.label ?? '') }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchProduct')}\n allowCreate\n createLabel={t('inventory.recipeForm.createProduct')}\n onCreate={async (q) => {\n const p = await quickCreateProduct(q, 'sale')\n if (p) { setProductId(p.id); setProductName(p.name) }\n }}\n />\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.yieldQuantity')}</label>\n <input type=\"number\" min={0.01} step={0.01} value={yieldQuantity} onChange={(e) => setYieldQuantity(Number(e.target.value) || 1)} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.prepTime')}</label>\n <input type=\"number\" min={0} value={prepTime} onChange={(e) => setPrepTime(e.target.value)} placeholder=\"—\" className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring\" />\n </div>\n </div>\n\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.recipeForm.instructions')}</label>\n <textarea value={instructions} onChange={(e) => setInstructions(e.target.value)} rows={4} placeholder={t('inventory.recipeForm.instructionsPlaceholder')} className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\" />\n </div>\n </div>\n\n {/* Right: Ingredients */}\n <div className=\"lg:col-span-2 rounded-card border bg-card shadow-sm overflow-hidden flex flex-col\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b\">\n <h3 className=\"text-sm font-semibold\">{t('inventory.recipeForm.ingredients')}</h3>\n <button onClick={addIngredient} className=\"inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors\">\n <Plus className=\"h-3 w-3\" /> {t('inventory.recipeForm.addIngredient')}\n </button>\n </div>\n\n <div className=\"flex-1\">\n {ingredients.length === 0 ? (\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground\">{t('inventory.recipeForm.noIngredients')}</p>\n <button onClick={addIngredient} className=\"text-xs text-primary hover:underline mt-1\">{t('inventory.recipeForm.addFirstIngredient')}</button>\n </div>\n ) : (\n <div className=\"divide-y\">\n {/* Header */}\n <div className=\"grid grid-cols-12 gap-2 px-4 py-2 text-[10px] font-medium text-muted-foreground uppercase tracking-wider bg-muted/20\">\n <div className=\"col-span-5\">{t('inventory.recipeForm.ingredient')}</div>\n <div className=\"col-span-2\">{t('inventory.recipeForm.quantity')}</div>\n <div className=\"col-span-4\">{t('inventory.recipeForm.notes')}</div>\n <div className=\"col-span-1\" />\n </div>\n {ingredients.map((ing, idx) => (\n <div key={ing._id} className=\"grid grid-cols-12 gap-2 px-4 py-2.5 items-center group\">\n <div className=\"col-span-5\">\n <SearchSelect\n value={ing.productId}\n displayValue={ing.productName}\n onChange={(id, opt) => updateIngredient(ing._id, { productId: id, productName: opt?.label ?? '' })}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchIngredient')}\n allowCreate\n createLabel={t('inventory.recipeForm.createIngredient')}\n onCreate={async (q) => {\n const p = await quickCreateProduct(q, 'ingredient')\n if (p) updateIngredient(ing._id, { productId: p.id, productName: p.name })\n }}\n />\n </div>\n <div className=\"col-span-2\">\n <input\n type=\"number\"\n min={0.01}\n step={0.01}\n value={ing.quantity}\n onChange={(e) => updateIngredient(ing._id, { quantity: Number(e.target.value) || 0 })}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div className=\"col-span-4\">\n <input\n type=\"text\"\n value={ing.notes}\n onChange={(e) => updateIngredient(ing._id, { notes: e.target.value })}\n placeholder={t('inventory.recipeForm.notesPlaceholder')}\n className=\"w-full rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n <div className=\"col-span-1 flex justify-end\">\n <button onClick={() => removeIngredient(ing._id)} className=\"p-1 text-muted-foreground opacity-0 group-hover:opacity-100 hover:text-destructive transition-all\">\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n {ingredients.length > 0 && (\n <div className=\"px-4 py-3 border-t bg-muted/20 text-xs text-muted-foreground\">\n {t('inventory.recipeForm.ingredientsConfigured', { configured: String(ingredients.filter((i) => i.productId).length), total: String(ingredients.length) })}\n </div>\n )}\n </div>\n </div>\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { AlertTriangle } from 'lucide-react'\nimport { SearchSelect, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { Product, Recipe, RecipeGaps } from '../types'\n\n/**\n * What the assistant proposed and could not match to the catalogue, offered\n * back for the user to pick or create. Without this the AI path dead-ends on\n * \"she mentioned bacon and it is not in the recipe\" — the recovery loop is what\n * made the legacy feature usable.\n */\nexport function RecipeGapsPanel({ recipe, gaps, onResolved }: {\n recipe: Recipe\n gaps: RecipeGaps\n onResolved: () => void | Promise<void>\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [busy, setBusy] = useState(false)\n\n const unmatched = gaps.unmatchedIngredients ?? []\n if (unmatched.length === 0 && !gaps.productHint) return null\n\n async function searchProducts(query: string) {\n const result = await provider.getProducts({ search: query, pageSize: 10 })\n return result.data.map((p) => ({ id: p.id, label: p.name, subtitle: p.sku ?? p.productType, data: p }))\n }\n\n async function quickCreate(name: string, productType: 'ingredient' | 'sale'): Promise<Product | null> {\n try {\n return await provider.createProduct({ name, productType })\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.createFailed'), { description: err?.message })\n return null\n }\n }\n\n function remainingGaps(index: number): RecipeGaps {\n return { ...gaps, unmatchedIngredients: unmatched.filter((_, i) => i !== index) }\n }\n\n async function linkIngredient(index: number, productId: string) {\n const gap = unmatched[index]\n setBusy(true)\n try {\n await provider.addRecipeIngredient(recipe.id, {\n productId,\n quantity: Number(gap?.quantity) > 0 ? Number(gap.quantity) : 1,\n notes: gap?.notes,\n })\n await provider.updateRecipe(recipe.id, { metadata: remainingGaps(index) as Record<string, unknown> })\n await onResolved()\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.linkFailed'), { description: err?.message })\n } finally {\n setBusy(false)\n }\n }\n\n async function linkProduct(productId: string) {\n setBusy(true)\n try {\n const { productHint: _dropped, ...rest } = gaps\n await provider.updateRecipe(recipe.id, { productId, metadata: rest as Record<string, unknown> })\n await onResolved()\n } catch (err: any) {\n toast.error(t('inventory.recipeGaps.linkFailed'), { description: err?.message })\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div className=\"rounded-card border border-warning/40 bg-warning/5 p-4 space-y-3\">\n <div className=\"flex items-start gap-2\">\n <AlertTriangle className=\"h-4 w-4 text-warning shrink-0 mt-px\" />\n <div>\n <h3 className=\"text-sm font-semibold text-foreground\">{t('inventory.recipeGaps.title')}</h3>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.recipeGaps.description')}</p>\n </div>\n </div>\n\n <div className={`space-y-2 ${busy ? 'opacity-60 pointer-events-none' : ''}`}>\n {gaps.productHint && (\n <div className=\"grid gap-2 sm:grid-cols-2 items-center\">\n <p className=\"text-xs\">\n <span className=\"text-muted-foreground\">{t('inventory.recipeGaps.produces')}</span>{' '}\n <strong className=\"text-foreground\">{gaps.productHint}</strong>\n </p>\n <SearchSelect\n value=\"\"\n onChange={(id) => { if (id) void linkProduct(id) }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchProduct')}\n allowCreate\n createLabel={t('inventory.recipeForm.createProduct')}\n onCreate={async (q) => {\n const p = await quickCreate(q, 'sale')\n if (p) await linkProduct(p.id)\n }}\n />\n </div>\n )}\n\n {unmatched.map((gap, index) => (\n <div key={`${gap.name}-${index}`} className=\"grid gap-2 sm:grid-cols-2 items-center\">\n <p className=\"text-xs\">\n <strong className=\"text-foreground\">{gap.name || t('inventory.recipeGaps.unnamed')}</strong>\n {Number(gap.quantity) > 0 && <span className=\"text-muted-foreground\"> · {gap.quantity}</span>}\n {gap.notes && <span className=\"text-muted-foreground\"> · {gap.notes}</span>}\n </p>\n <SearchSelect\n value=\"\"\n onChange={(id) => { if (id) void linkIngredient(index, id) }}\n onSearch={searchProducts}\n placeholder={t('inventory.recipeForm.searchIngredient')}\n allowCreate\n createLabel={t('inventory.recipeForm.createIngredient')}\n onCreate={async (q) => {\n const p = await quickCreate(q, 'ingredient')\n if (p) await linkIngredient(index, p.id)\n }}\n />\n </div>\n ))}\n </div>\n </div>\n )\n}\n","import { errorMessage } from '@fayz-ai/core'\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { AlertTriangle, BookOpen, Clock, Coins, Layers, Package } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { DataTable, SubpageHeader } from '@fayz-ai/ui'\nimport type { Recipe, RecipeGaps, RecipeIngredient } from '../types'\nimport { CMV_ALERT_THRESHOLD, cmvPercent, ingredientUnitCost, isCmvHigh, recipeCost } from '../lib/recipe-cost'\nimport { RecipeGapsPanel } from '../components/RecipeGapsPanel'\n\n/** What the assistant could not resolve, as the RPC stored it. */\nfunction readGaps(recipe: Recipe | null): RecipeGaps {\n const meta = recipe?.metadata as RecipeGaps | undefined\n return {\n unmatchedIngredients: Array.isArray(meta?.unmatchedIngredients) ? meta!.unmatchedIngredients : undefined,\n productHint: typeof meta?.productHint === 'string' ? meta.productHint : undefined,\n }\n}\n\nfunction DetailSkeleton() {\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-12 w-12 rounded-xl bg-muted/40 animate-pulse\" />\n <div className=\"space-y-2 flex-1\">\n <div className=\"h-5 w-40 rounded bg-muted/40 animate-pulse\" />\n <div className=\"h-3 w-24 rounded bg-muted/30 animate-pulse\" />\n </div>\n </div>\n <div className=\"rounded-xl border divide-y\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"h-3 w-20 rounded bg-muted/30 animate-pulse\" />\n <div className=\"flex-1\" />\n <div className=\"h-3 w-16 rounded bg-muted/40 animate-pulse\" />\n </div>\n ))}\n </div>\n <div className=\"rounded-xl border p-4 space-y-2\">\n {[1, 2, 3, 4].map((i) => (\n <div key={i} className=\"flex items-center gap-3\">\n <div className=\"h-3.5 w-6 rounded bg-muted/30 animate-pulse\" />\n <div className=\"h-3.5 flex-1 rounded bg-muted/30 animate-pulse\" />\n <div className=\"h-3.5 w-12 rounded bg-muted/40 animate-pulse\" />\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport function RecipeDetailView({ recipeId, onBack }: { recipeId: string; onBack: () => void }) {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const provider = useInventoryProvider()\n const [recipe, setRecipe] = useState<Recipe | null>(null)\n const [ingredients, setIngredients] = useState<RecipeIngredient[]>([])\n const [loading, setLoading] = useState(true)\n const [loadError, setLoadError] = useState('')\n\n const load = React.useCallback(async () => {\n try {\n const [r, ings] = await Promise.all([\n provider.getRecipeById(recipeId),\n provider.getRecipeIngredients(recipeId),\n ])\n setRecipe(r)\n setIngredients(ings.sort((a, b) => a.displayOrder - b.displayOrder))\n setLoadError('')\n } catch (error) {\n setLoadError(errorMessage(error))\n }\n }, [recipeId, provider])\n\n useEffect(() => {\n setLoading(true)\n void load().finally(() => setLoading(false))\n }, [load])\n\n const totalCost = useMemo(() => recipeCost(ingredients), [ingredients])\n const cmv = useMemo(() => cmvPercent(totalCost, recipe?.productSalePrice), [totalCost, recipe?.productSalePrice])\n const gaps = useMemo(() => readGaps(recipe), [recipe])\n\n if (loading) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={t('inventory.recipeDetail.loading')}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n />\n <DetailSkeleton />\n </div>\n )\n }\n\n if (loadError) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader title={t('inventory.recipeDetail.loadFailed')} icon=\"BookOpen\" onBack={onBack} parentLabel={t('inventory.nav.recipes')} />\n <div className=\"flex flex-col items-center justify-center rounded-xl border-2 border-dashed border-destructive/30 bg-destructive/5 px-6 py-16 text-center\">\n <AlertTriangle className=\"mb-3 h-8 w-8 text-destructive\" />\n <p className=\"font-medium\">{t('inventory.recipeDetail.loadFailed')}</p>\n <p className=\"mt-1 max-w-xl text-xs text-muted-foreground\">{loadError}</p>\n <button type=\"button\" onClick={() => { setLoading(true); void load().finally(() => setLoading(false)) }} className=\"mt-4 rounded-button border bg-card px-4 py-2 text-sm font-medium shadow-button hover:bg-muted\">\n {t('inventory.recipeDetail.retry')}\n </button>\n </div>\n </div>\n )\n }\n\n if (!recipe) {\n return (\n <div className=\"space-y-6\">\n <SubpageHeader\n title={t('inventory.recipeDetail.notFound')}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n />\n <div className=\"flex flex-col items-center justify-center py-16 text-center rounded-lg border-2 border-dashed border-muted\">\n <BookOpen className=\"h-8 w-8 text-muted-foreground/30 mb-2\" />\n <p className=\"text-sm text-muted-foreground\">{t('inventory.recipeDetail.notFound')}</p>\n <button onClick={onBack} className=\"text-xs text-primary hover:underline mt-1\">{t('inventory.recipeDetail.backToList')}</button>\n </div>\n </div>\n )\n }\n\n // A ficha whose ingredients carry no notes wastes a column on a row of dashes,\n // and the table is already wide enough to scroll on a laptop.\n const anyNotes = ingredients.some((i) => (i.notes ?? '').trim().length > 0)\n\n const ingredientColumns: ColumnDef<RecipeIngredient, any>[] = [\n {\n id: 'index', header: '#',\n cell: ({ row }) => <span className=\"text-xs text-muted-foreground\">{row.index + 1}</span>,\n },\n {\n accessorKey: 'productName', header: t('inventory.recipeDetail.ingredient'),\n cell: ({ getValue }) => <span className=\"font-medium\">{(getValue() as string) || '—'}</span>,\n },\n {\n accessorKey: 'quantity', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.quantity')}</span>,\n cell: ({ getValue }) => <span className=\"block text-right tabular-nums\">{getValue() as number}</span>,\n },\n {\n accessorKey: 'unitName', header: t('inventory.recipeDetail.unit'),\n cell: ({ getValue }) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n },\n ...(anyNotes ? [{\n accessorKey: 'notes', header: t('inventory.recipeDetail.notes'),\n cell: ({ getValue }: any) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) || '—'}</span>,\n }] : []),\n {\n id: 'unitCost', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.unitCost')}</span>,\n cell: ({ row }) => (\n <span className=\"block text-right text-muted-foreground tabular-nums\">\n {formatCurrency(ingredientUnitCost(row.original.costBasis), currency)}\n </span>\n ),\n },\n {\n id: 'cost', header: () => <span className=\"block text-right\">{t('inventory.recipeDetail.cost')}</span>,\n cell: ({ row }) => (\n <span className=\"block text-right font-medium tabular-nums\">\n {formatCurrency(ingredientUnitCost(row.original.costBasis) * (row.original.quantity || 0), currency)}\n </span>\n ),\n },\n ]\n\n return (\n <div className=\"space-y-6\">\n {/* O mesmo cabeçalho de subpágina de todas as outras telas: o título, o\n caminho de volta e o estado à direita. O herói desenhado à mão que\n vivia aqui repetia o nome logo abaixo do rastro e escolhia a própria\n altura — duas gramáticas de topo dentro do mesmo app. */}\n <SubpageHeader\n title={recipe.name}\n subtitle={recipe.description}\n icon=\"BookOpen\"\n onBack={onBack}\n parentLabel={t('inventory.nav.recipes')}\n actions={\n recipe.isActive ? (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-success\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-success\" /> {t('inventory.recipeDetail.active')}\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-muted-foreground/50\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-muted-foreground/30\" /> {t('inventory.recipeDetail.inactive')}\n </span>\n )\n }\n />\n\n <RecipeGapsPanel recipe={recipe} gaps={gaps} onResolved={load} />\n\n <div className=\"grid gap-4 lg:grid-cols-3\">\n {/* Left, and wide: the ingredients ARE the recipe. The list that gets\n read is the one that gets the room — it was squeezed into a third of\n the page while four numbers took the other two. */}\n <div className=\"lg:col-span-2\">\n <h3 className=\"text-sm font-semibold text-foreground mb-2\">{t('inventory.recipeDetail.ingredientsTitle')}</h3>\n {ingredients.length === 0 ? (\n <div className=\"rounded-xl border p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.recipeDetail.noIngredients')}</p>\n </div>\n ) : (\n <DataTable columns={ingredientColumns} data={ingredients} variant=\"card\" />\n )}\n </div>\n\n {/* Right: the facts about the recipe, beside the list they describe. */}\n <div className=\"space-y-4\">\n {/* Metrics */}\n <div className=\"rounded-xl border divide-y\">\n {recipe.productName && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.produces')}</span>\n <span className=\"text-sm font-medium\">{recipe.productName}</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Layers className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.yield')}</span>\n <span className=\"text-sm font-medium\">{recipe.yieldQuantity}{recipe.yieldUnitName ? ` ${recipe.yieldUnitName}` : ''}</span>\n </div>\n {recipe.preparationTimeMinutes != null && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Clock className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.prepTime')}</span>\n <span className=\"text-sm font-medium\">{recipe.preparationTimeMinutes} min</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Layers className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.ingredientCount')}</span>\n <span className=\"text-sm font-medium\">{ingredients.length}</span>\n </div>\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.totalCost')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(totalCost, currency)}</span>\n </div>\n {recipe.yieldQuantity > 1 && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.costPerYield')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(totalCost / recipe.yieldQuantity, currency)}</span>\n </div>\n )}\n {recipe.productSalePrice != null && recipe.productSalePrice > 0 && (\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Package className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.salePrice')}</span>\n <span className=\"text-sm font-medium tabular-nums\">{formatCurrency(recipe.productSalePrice, currency)}</span>\n </div>\n )}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Coins className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <span className=\"text-xs text-muted-foreground flex-1\">{t('inventory.recipeDetail.cmv')}</span>\n {cmv == null ? (\n <span className=\"text-xs text-muted-foreground\">{t('inventory.recipeDetail.cmvUnknown')}</span>\n ) : (\n <span className={`text-sm font-medium tabular-nums ${isCmvHigh(cmv) ? 'text-destructive' : 'text-success'}`}>\n {cmv.toFixed(1)}%\n </span>\n )}\n </div>\n </div>\n\n {isCmvHigh(cmv) && (\n <p className=\"flex items-start gap-1.5 text-[11px] text-destructive\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0 mt-px\" />\n {t('inventory.recipeDetail.cmvHigh', { threshold: String(CMV_ALERT_THRESHOLD) })}\n </p>\n )}\n\n {/* Instructions */}\n {recipe.instructions && (\n <div>\n <h3 className=\"text-sm font-semibold text-foreground mb-1\">{t('inventory.recipeDetail.instructions')}</h3>\n <div className=\"rounded-card border bg-card shadow-sm px-4 py-3\">\n <p className=\"text-xs text-muted-foreground whitespace-pre-wrap leading-relaxed\">{recipe.instructions}</p>\n </div>\n </div>\n )}\n\n {/* Dates */}\n <div className=\"flex items-center gap-4 text-[10px] text-muted-foreground/50\">\n <span>{t('inventory.recipeDetail.created')} {recipe.createdAt?.slice(0, 10)}</span>\n <span>{t('inventory.recipeDetail.updated')} {recipe.updatedAt?.slice(0, 10)}</span>\n </div>\n </div>\n\n </div>\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { TeachMeLink } from '@fayz-ai/admin'\nimport { ClipboardCheck } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport {\n ListView, SubpageHeader, Button, Badge, toast, DraftCommitBar,\n Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryStore, useInventoryConfig, formatCurrency } from '../context'\nimport { summarizeCount } from '../lib/stock-count'\nimport type { StockCountItem, UsageAuditCorrection, UsageAuditEntry } from '../types'\n\n// ---------------------------------------------------------------------------\n// AUDITORIA DE USO — uma CONTAGEM, não um formulário por linha.\n//\n// A conferência de consumo é o mesmo gesto de uma contagem de estoque: a\n// pessoa desce a lista digitando o que realmente saiu e explica o conjunto uma\n// vez. Por isso esta tela empresta da contagem tudo o que pode: o campo aberto\n// na própria linha, Enter descendo para o próximo, a aritmética de divergência\n// (`summarizeCount`, que já sabe que linha em branco NÃO é linha contada zero)\n// e o fechamento em lote com um motivo só.\n//\n// O QUE ELA NÃO EMPRESTA, DE PROPÓSITO: a contagem tem sessão em banco e grava\n// cada número ao sair do campo, porque alguém pode fechar o navegador no meio\n// do estoque frio — e porque o modo cego precisa que o servidor guarde o\n// número. A auditoria não tem sessão e não deve ter: a migration 001 recusou\n// uma fila justamente para não existir um segundo lugar guardando a mesma\n// quantidade. Então o rascunho vive AQUI, na tela, e só o \"Aplicar\" escreve.\n// ---------------------------------------------------------------------------\n\nconst keyOf = (entry: Pick<UsageAuditEntry, 'itemId' | 'productId'>) => `${entry.itemId}:${entry.productId}`\n\n/** Trailing zeros on a quantity read as precision the count never had. */\nfunction formatQuantity(value: number): string {\n return String(Number(value.toFixed(4)))\n}\n\nfunction formatSigned(value: number): string {\n return value > 0 ? `+${formatQuantity(value)}` : formatQuantity(value)\n}\n\nfunction formatUsedAt(iso: string, locale: string): string {\n const date = new Date(iso)\n if (Number.isNaN(date.getTime())) return '—'\n return date.toLocaleString(locale, {\n day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit',\n })\n}\n\n/**\n * Empty is \"nobody looked at this line\", never zero — the same rule the count\n * enforces. `null` is untouched, `undefined` is a number that is not a number.\n */\nfunction parseQuantity(raw: string | undefined): number | null | undefined {\n const trimmed = (raw ?? '').trim()\n if (trimmed === '') return null\n // pt-BR types \"2,5\". `type=number` swallows that comma and hands back an\n // empty string, which is how a correction becomes a silent no-op.\n const parsed = Number(trimmed.replace(',', '.'))\n if (!Number.isFinite(parsed) || parsed < 0) return undefined\n return parsed\n}\n\n/**\n * The counted field, on the row.\n *\n * It is controlled by the page — the summary and the bar need every keystroke —\n * and that is only safe because the column definitions above are memoised on\n * stable dependencies. Rebuild them per keystroke and the cell remounts, which\n * takes the caret with it.\n */\nconst CountedField = React.memo(function CountedField({\n entry, value, onChange, onEnter, registerRef, label,\n}: {\n entry: UsageAuditEntry\n value: string\n onChange: (key: string, raw: string) => void\n onEnter: (key: string) => void\n registerRef: (key: string, el: HTMLInputElement | null) => void\n label: string\n}) {\n const key = keyOf(entry)\n const parsed = parseQuantity(value)\n const invalid = parsed === undefined\n const delta = parsed == null || invalid ? null : parsed - entry.netQuantity\n\n return (\n <div className=\"flex items-center justify-end gap-2 whitespace-nowrap\">\n <span\n className={`w-14 text-right text-xs tabular-nums ${\n delta === null || delta === 0 ? 'text-muted-foreground'\n : delta > 0 ? 'text-destructive' : 'text-success'\n }`}\n >\n {delta === null || delta === 0 ? '' : formatSigned(delta)}\n </span>\n <input\n ref={(el) => registerRef(key, el)}\n type=\"text\"\n inputMode=\"decimal\"\n aria-label={`${label} — ${entry.productName ?? ''}`.trim()}\n aria-invalid={invalid || undefined}\n value={value}\n placeholder={formatQuantity(entry.netQuantity)}\n onChange={(e) => onChange(key, e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); onEnter(key) } }}\n className={`w-24 shrink-0 rounded-input border bg-card px-3 py-2.5 text-right text-sm font-medium tabular-nums shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring ${\n invalid ? 'border-destructive' : 'border-input'\n }`}\n />\n </div>\n )\n})\n\n/**\n * A observação, uma vez, para o lote inteiro — a mensagem de commit da\n * conferência. Vai pelo portal do design system: um diálogo desenhado à mão\n * herda a cor do que o abriu e sai quase-branco sobre cartão branco.\n */\nfunction ApplyBatchModal({ open, lines, saving, onCancel, onConfirm }: {\n open: boolean\n lines: Array<{ entry: UsageAuditEntry; quantity: number }>\n saving: boolean\n onCancel: () => void\n onConfirm: (reason: string) => void\n}) {\n const t = useTranslation()\n const [reason, setReason] = useState('')\n\n useEffect(() => { if (open) setReason('') }, [open])\n if (!open) return null\n\n const canSave = reason.trim().length > 0 && !saving\n\n return (\n <Modal open onOpenChange={(next) => { if (!next && !saving) onCancel() }}>\n <ModalContent size=\"sm\">\n <ModalHeader>\n <ModalTitle>{lines.length === 1\n ? t('inventory.usageAudit.applyTitleOne')\n : t('inventory.usageAudit.applyTitle', { count: String(lines.length) })}</ModalTitle>\n <ModalDescription>{t('inventory.usageAudit.applyDescription')}</ModalDescription>\n </ModalHeader>\n <ModalBody className=\"space-y-4\">\n {/* fz-container/fz-fields, não `sm:` — dentro de um diálogo de 448px\n o breakpoint mede a JANELA e insiste em duas colunas de 200. */}\n <div className=\"fz-container rounded-2xl border border-border bg-muted/40 px-3 py-2\">\n <ul className=\"space-y-1 text-xs\">\n {lines.map(({ entry, quantity }) => {\n const unit = entry.unitAbbreviation ? ` ${entry.unitAbbreviation}` : ''\n return (\n <li key={keyOf(entry)} className=\"flex items-baseline justify-between gap-3\">\n <span className=\"min-w-0 truncate\">\n {entry.productName ?? t('inventory.usageAudit.unnamedProduct')}\n </span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">\n {formatQuantity(entry.netQuantity)}{unit} → <span className=\"font-medium text-foreground\">\n {formatQuantity(quantity)}{unit}\n </span>\n </span>\n </li>\n )\n })}\n </ul>\n </div>\n\n <div>\n <label htmlFor=\"usage-audit-batch-reason\" className=\"text-xs font-medium text-muted-foreground\">\n {t('inventory.usageAudit.reason')}\n </label>\n <textarea\n id=\"usage-audit-batch-reason\"\n autoFocus\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={3}\n placeholder={t('inventory.usageAudit.batchReasonPlaceholder')}\n className=\"w-full mt-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring resize-none\"\n />\n {/* Um botão morto em silêncio faz a pessoa clicar de novo mais\n forte. Ele diz o que falta. */}\n <p className={`mt-1 text-[11px] ${reason.trim() ? 'text-muted-foreground' : 'text-warning'}`}>\n {reason.trim()\n ? t('inventory.usageAudit.batchReasonHint')\n : t('inventory.usageAudit.batchReasonRequired')}\n </p>\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" size=\"sm\" onClick={onCancel} disabled={saving}>\n {t('inventory.usageAudit.cancel')}\n </Button>\n <Button size=\"sm\" onClick={() => onConfirm(reason.trim())} disabled={!canSave}>\n {t('inventory.usageAudit.applyConfirm')}\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\nexport function UsageAuditView() {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const entries = useInventoryStore((s) => s.usageAudit)\n const total = useInventoryStore((s) => s.usageAuditTotal)\n const loading = useInventoryStore((s) => s.usageAuditLoading)\n const fetchUsageAudit = useInventoryStore((s) => s.fetchUsageAudit)\n const correctUsageBatch = useInventoryStore((s) => s.correctUsageBatch)\n\n const [search, setSearch] = useState('')\n const [tag, setTag] = useState<string | undefined>(undefined)\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [confirming, setConfirming] = useState(false)\n const [saving, setSaving] = useState(false)\n\n useEffect(() => {\n fetchUsageAudit({ search: search || undefined, divergentOnly: tag === 'divergent' })\n .catch((err: any) => toast.error(t('inventory.usageAudit.loadFailed'), { description: err?.message }))\n }, [search, tag])\n\n const locale = currency.locale ?? 'pt-BR'\n\n // Enter desce para o próximo campo, como na contagem. A ordem é a da lista\n // em tela, guardada numa ref para que as colunas não precisem ser refeitas a\n // cada tecla — refazê-las remonta a célula e leva o foco embora.\n const fieldRefs = useRef(new Map<string, HTMLInputElement | null>())\n const order = useRef<string[]>([])\n order.current = entries.map(keyOf)\n\n const registerRef = useCallback((key: string, el: HTMLInputElement | null) => {\n if (el) fieldRefs.current.set(key, el)\n else fieldRefs.current.delete(key)\n }, [])\n\n const focusNext = useCallback((key: string) => {\n const index = order.current.indexOf(key)\n const next = order.current[index + 1]\n if (next) fieldRefs.current.get(next)?.focus()\n }, [])\n\n const setDraft = useCallback((key: string, raw: string) => {\n setDrafts((prev) => ({ ...prev, [key]: raw }))\n }, [])\n\n const draftsRef = useRef(drafts)\n draftsRef.current = drafts\n\n // A aritmética é a da contagem, literalmente: a linha da auditoria vira uma\n // linha de contagem onde \"o sistema\" é o que o razão já baixou.\n const summary = useMemo(() => summarizeCount(entries.map((entry) => ({\n id: keyOf(entry),\n productId: entry.productId,\n systemQuantity: entry.netQuantity,\n countedQuantity: parseQuantity(drafts[keyOf(entry)]) ?? undefined,\n unitCost: entry.netQuantity ? entry.totalCost / entry.netQuantity : 0,\n }) as StockCountItem)), [entries, drafts])\n\n const pending = useMemo(() => entries\n .map((entry) => ({ entry, quantity: parseQuantity(drafts[keyOf(entry)]) }))\n .filter((line): line is { entry: UsageAuditEntry; quantity: number } =>\n typeof line.quantity === 'number' && line.quantity !== line.entry.netQuantity),\n [entries, drafts])\n\n const invalidCount = useMemo(\n () => entries.filter((entry) => parseQuantity(drafts[keyOf(entry)]) === undefined).length,\n [entries, drafts])\n\n async function apply(reason: string) {\n setSaving(true)\n try {\n const lines: UsageAuditCorrection[] = pending.map(({ entry, quantity }) => ({\n itemId: entry.itemId, productId: entry.productId, quantity,\n }))\n const outcome = await correctUsageBatch({ reason, lines })\n toast.success(outcome.linesApplied === 1\n ? t('inventory.usageAudit.batchAppliedOne')\n : t('inventory.usageAudit.batchApplied', { count: String(outcome.linesApplied) }))\n setDrafts({})\n setConfirming(false)\n } catch (err: any) {\n toast.error(t('inventory.usageAudit.batchFailed'), { description: err?.message })\n } finally {\n setSaving(false)\n }\n }\n\n const columns: ColumnDef<UsageAuditEntry, any>[] = useMemo(() => [\n {\n id: 'product', header: t('inventory.usageAudit.columnProduct'),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n return (\n <div className=\"min-w-[10rem]\">\n <div className=\"font-medium\">{entry.productName ?? t('inventory.usageAudit.unnamedProduct')}</div>\n {/* The sold line only earns a second row when it is not the product\n itself — \"Shampoo X / Shampoo X\" says nothing twice. */}\n {entry.itemName && entry.itemName !== entry.productName && (\n <div className=\"text-xs text-muted-foreground\">{entry.itemName}</div>\n )}\n </div>\n )\n },\n },\n {\n id: 'quantity', header: t('inventory.usageAudit.columnQuantity'),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n const unit = entry.unitAbbreviation ? ` ${entry.unitAbbreviation}` : ''\n // The standard only earns a line when it disagrees — that is the V1\n // reading: the quiet row is the one that matched.\n const off = entry.variance != null && entry.variance !== 0\n return (\n <div className=\"whitespace-nowrap\">\n <span className={off ? 'font-medium text-warning' : 'font-medium'}>\n {formatQuantity(entry.netQuantity)}{unit}\n </span>\n {off && entry.standardQuantity != null && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {t('inventory.usageAudit.standard')}: {formatQuantity(entry.standardQuantity)}{unit}\n </span>\n )}\n {entry.isCorrected && (\n <Badge variant=\"outline\" className=\"ml-2 text-[10px]\">\n {t('inventory.usageAudit.corrected')}\n </Badge>\n )}\n </div>\n )\n },\n },\n {\n id: 'location', header: t('inventory.usageAudit.columnLocation'),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n return (\n <span className=\"text-xs text-muted-foreground whitespace-nowrap\">\n {entry.stockLocationName ?? t('inventory.usageAudit.noLocation')}\n {entry.locationCount > 1 && ` +${entry.locationCount - 1}`}\n </span>\n )\n },\n },\n {\n id: 'usedAt', header: t('inventory.usageAudit.columnWhen'),\n cell: ({ row }: any) => (\n <span className=\"text-xs text-muted-foreground whitespace-nowrap\">\n {formatUsedAt((row.original as UsageAuditEntry).usedAt, locale)}\n </span>\n ),\n },\n {\n id: 'performedBy', header: t('inventory.usageAudit.columnPerformedBy'),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n return (\n <span className=\"text-xs whitespace-nowrap\">\n {entry.performedByName ?? <span className=\"text-muted-foreground\">—</span>}\n </span>\n )\n },\n },\n {\n id: 'customer', header: t('inventory.usageAudit.columnCustomer'),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n return (\n <span className=\"text-xs text-muted-foreground whitespace-nowrap\">\n {entry.customerName ?? '—'}\n </span>\n )\n },\n },\n {\n id: 'cost', header: t('inventory.usageAudit.columnCost'),\n cell: ({ row }: any) => (\n <span className=\"block text-right text-xs text-muted-foreground\">\n {formatCurrency((row.original as UsageAuditEntry).totalCost, currency)}\n </span>\n ),\n },\n {\n // O campo fica ABERTO na linha: conferir é descer a lista digitando,\n // não abrir um diálogo por item.\n id: 'counted', header: () => (\n <span className=\"block text-right\">{t('inventory.usageAudit.columnCounted')}</span>\n ),\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n return (\n <CountedField\n entry={entry}\n value={draftsRef.current[keyOf(entry)] ?? ''}\n onChange={setDraft}\n onEnter={focusNext}\n registerRef={registerRef}\n label={t('inventory.usageAudit.columnCounted')}\n />\n )\n },\n },\n ], [currency, locale, t, setDraft, focusNext, registerRef])\n\n const costDelta = summary.varianceValue\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader\n title={t('inventory.usageAudit.title')}\n subtitle={t('inventory.usageAudit.subtitle')}\n actions={\n <TeachMeLink\n feature=\"inventory.auditoria-de-uso\"\n title=\"Auditoria de Uso\"\n about=\"O que os atendimentos consumiram de verdade, lado a lado com o que era o padrão. É depois da baixa: o atendimento já consumiu, e corrigir lança a diferença no razão. Digite na própria linha e aplique tudo de uma vez, com uma observação só.\"\n />\n }\n />\n\n <ListView<UsageAuditEntry>\n columns={columns}\n data={entries}\n loading={loading}\n total={total}\n getRowId={(row) => keyOf(row)}\n searchPlaceholder={t('inventory.usageAudit.searchPlaceholder')}\n search={search}\n onSearchChange={setSearch}\n searchDebounce={300}\n tags={[{ value: 'divergent', label: t('inventory.usageAudit.filterDivergent') }]}\n tagsLabel={t('inventory.usageAudit.filterLabel')}\n allTagLabel={t('inventory.usageAudit.filterAll')}\n activeTag={tag}\n onTagChange={setTag}\n emptyMessage={tag === 'divergent'\n ? t('inventory.usageAudit.emptyDivergent')\n : t('inventory.usageAudit.empty')}\n />\n\n <DraftCommitBar\n open={pending.length > 0 || invalidCount > 0}\n icon={ClipboardCheck}\n title={pending.length === 0\n ? t('inventory.usageAudit.draftCheck')\n : pending.length === 1\n ? t('inventory.usageAudit.draftOne')\n : t('inventory.usageAudit.draftMany', { count: String(pending.length) })}\n hint={costDelta === 0\n ? t('inventory.usageAudit.draftHint')\n : t('inventory.usageAudit.draftCost', { value: formatCurrency(costDelta, currency) })}\n commitDisabledReason={invalidCount > 0\n ? t('inventory.usageAudit.draftInvalid', { count: String(invalidCount) })\n : pending.length === 0\n ? t('inventory.usageAudit.draftNothing')\n : undefined}\n discardLabel={t('inventory.usageAudit.discard')}\n onDiscard={() => setDrafts({})}\n commitLabel={t('inventory.usageAudit.apply', { count: String(pending.length) })}\n onCommit={() => setConfirming(true)}\n busy={saving}\n />\n\n <ApplyBatchModal\n open={confirming}\n lines={pending}\n saving={saving}\n onCancel={() => setConfirming(false)}\n onConfirm={(reason) => void apply(reason)}\n />\n </div>\n )\n}\n","import React from 'react'\nimport { SettingsGroup, ToggleRow, useTenantPluginSettings } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\n\n// Per-tenant defaults = the values that used to be hardcoded here. Persisted +\n// re-hydrated per tenant; behavioural consumption is a follow-up.\nconst INVENTORY_DEFAULTS = {\n lowStockAlerts: true,\n requireReason: true,\n autoDeduct: false,\n requireSku: false,\n allowNegative: false,\n lowStockEmail: false,\n expiryWarnings: true,\n}\n\nexport function InventoryGeneralSettings() {\n const t = useTranslation()\n const s = useTenantPluginSettings('inventory', INVENTORY_DEFAULTS)\n return (\n <div className=\"space-y-4\">\n <SettingsGroup title={t('inventory.settings.stockManagement')} description={t('inventory.settings.stockManagementDesc')}>\n <ToggleRow label={t('inventory.settings.lowStockAlerts')} description={t('inventory.settings.lowStockAlertsDesc')} checked={s.get('lowStockAlerts')} onChange={(v) => s.set('lowStockAlerts', v)} />\n <ToggleRow label={t('inventory.settings.requireReason')} description={t('inventory.settings.requireReasonDesc')} checked={s.get('requireReason')} onChange={(v) => s.set('requireReason', v)} />\n <ToggleRow label={t('inventory.settings.autoDeduct')} description={t('inventory.settings.autoDeductDesc')} checked={s.get('autoDeduct')} onChange={(v) => s.set('autoDeduct', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('inventory.settings.products')} description={t('inventory.settings.productsDesc')}>\n <ToggleRow label={t('inventory.settings.requireSku')} description={t('inventory.settings.requireSkuDesc')} checked={s.get('requireSku')} onChange={(v) => s.set('requireSku', v)} />\n <ToggleRow label={t('inventory.settings.allowNegative')} description={t('inventory.settings.allowNegativeDesc')} checked={s.get('allowNegative')} onChange={(v) => s.set('allowNegative', v)} />\n </SettingsGroup>\n\n <SettingsGroup title={t('inventory.settings.notifications')} description={t('inventory.settings.notificationsDesc')}>\n <ToggleRow label={t('inventory.settings.lowStockEmail')} description={t('inventory.settings.lowStockEmailDesc')} checked={s.get('lowStockEmail')} onChange={(v) => s.set('lowStockEmail', v)} />\n <ToggleRow label={t('inventory.settings.expiryWarnings')} description={t('inventory.settings.expiryWarningsDesc')} checked={s.get('expiryWarnings')} onChange={(v) => s.set('expiryWarnings', v)} />\n </SettingsGroup>\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { Package, Ruler, MapPin, ChevronRight, Check, Loader2 } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { Button } from '@fayz-ai/ui'\n\nconst STEPS = [\n { id: 'welcome', icon: Package, titleKey: 'inventory.onboarding.welcome', descKey: 'inventory.onboarding.description' },\n { id: 'units', icon: Ruler, titleKey: 'inventory.onboarding.units.title', descKey: 'inventory.onboarding.units.description' },\n { id: 'locations', icon: MapPin, titleKey: 'inventory.onboarding.locations.title', descKey: 'inventory.onboarding.locations.description' },\n]\n\nexport function InventoryOnboarding({ onComplete }: { onComplete: () => void | Promise<void> }) {\n const t = useTranslation()\n const [step, setStep] = useState(0)\n const [preparing, setPreparing] = useState(false)\n const [error, setError] = useState('')\n const current = STEPS[step]\n const isLast = step === STEPS.length - 1\n const Icon = current.icon\n\n async function complete() {\n if (preparing) return\n setPreparing(true)\n setError('')\n try {\n await onComplete()\n } catch {\n setError(t('inventory.onboarding.setupError'))\n } finally {\n setPreparing(false)\n }\n }\n\n return (\n <div className=\"flex items-center justify-center py-12\">\n <div className=\"w-full max-w-lg\">\n <div className=\"flex items-center gap-1 mb-8\">\n {STEPS.map((_, i) => (\n <div key={i} className={`h-1 flex-1 rounded-full transition-colors ${i <= step ? 'bg-primary' : 'bg-muted'}`} />\n ))}\n </div>\n <div className=\"rounded-card border bg-card p-8 text-center space-y-6 shadow-sm\">\n <div className=\"flex justify-center\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-primary/10\">\n <Icon className=\"h-8 w-8 text-primary\" />\n </div>\n </div>\n <div>\n <h2 className=\"text-xl font-bold\">{t(current.titleKey)}</h2>\n <p className=\"text-sm text-muted-foreground mt-2 max-w-sm mx-auto\">{t(current.descKey)}</p>\n </div>\n <div className=\"flex items-center justify-center gap-3 pt-2\">\n {step > 0 && (\n <Button variant=\"outline\" size=\"lg\" onClick={() => setStep(step - 1)}>{t('common.back')}</Button>\n )}\n {isLast ? (\n <Button variant=\"default\" size=\"lg\" onClick={() => void complete()} disabled={preparing}>\n {preparing ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Check className=\"h-4 w-4\" />}\n {preparing ? t('inventory.onboarding.preparing') : t('inventory.onboarding.start')}\n </Button>\n ) : (\n <Button variant=\"default\" size=\"lg\" onClick={() => setStep(step + 1)}>\n {step === 0 ? t('inventory.onboarding.getStarted') : t('common.continue')} <ChevronRight className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n {step === 0 && (\n <button onClick={() => void complete()} disabled={preparing} className=\"text-xs text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50\">\n {t('inventory.onboarding.skip')}\n </button>\n )}\n {error && <p role=\"alert\" className=\"text-sm text-destructive\">{error}</p>}\n </div>\n </div>\n </div>\n )\n}\n","import React, { useState, useMemo } from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ModulePage, PageTransition, type ModuleNavItem } from '@fayz-ai/ui'\nimport { InventoryContextProvider, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport type { InventoryUIState } from '../store'\nimport type { PluginRegistryDef, PluginQuickAction } from '@fayz-ai/core'\nimport { useModuleNavigation, ModuleActionBar, createViewRouter, PluginSettingsPanel } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { DashboardView } from './DashboardView'\nimport { ProductListView } from './ProductListView'\nimport { ProductCrudForm } from './ProductCrudForm'\nimport { ProductDetailView } from './ProductDetailView'\nimport { StockMovementView } from './StockMovementView'\nimport { MovementHistoryView } from './MovementHistoryView'\nimport { StockCountsView } from './StockCountsView'\nimport { StockCountFormView } from './StockCountFormView'\nimport { StockCountSessionView } from './StockCountSessionView'\nimport { RecipesView } from './RecipesView'\nimport { RecipeFormView } from './RecipeFormView'\nimport { RecipeDetailView } from './RecipeDetailView'\nimport { UsageAuditView } from './UsageAuditView'\nimport { InventoryGeneralSettings } from '../components/InventoryGeneralSettings'\nimport { InventoryOnboarding } from '../components/InventoryOnboarding'\n\nfunction buildNav(config: ResolvedInventoryConfig, view: string, navigate: (v: string) => void, t: (key: string) => string): ModuleNavItem[] {\n const items: ModuleNavItem[] = [\n { id: 'dashboard', label: t('inventory.nav.dashboard'), icon: 'BarChart3', active: view === 'dashboard', onClick: () => navigate('dashboard') },\n ...(config.modules.products ? [{\n id: 'products', label: t('inventory.nav.products'), icon: 'Package', active: view.startsWith('products'),\n children: [\n { id: 'products-new', label: t('inventory.nav.new'), active: view === 'products-new', onClick: () => navigate('products-new') },\n { id: 'products-list', label: t('inventory.nav.list'), active: view === 'products-list' || view.startsWith('products-detail:') || view.startsWith('products-stock:'), onClick: () => navigate('products-list') },\n ],\n } as ModuleNavItem] : []),\n {\n id: 'stock', label: t('inventory.nav.stock'), icon: 'ArrowUpCircle',\n children: [\n { id: 'stock-entry', label: t('inventory.nav.entry'), active: view === 'stock-entry', onClick: () => navigate('stock-entry') },\n { id: 'stock-exit', label: t('inventory.nav.exit'), active: view === 'stock-exit', onClick: () => navigate('stock-exit') },\n // Before History on purpose: the parent tab flattens to the LAST child,\n // and \"Stock\" has always landed on History.\n { id: 'stock-counts', label: t('inventory.nav.counts'), active: view === 'stock-counts' || view.startsWith('stock-counts'), onClick: () => navigate('stock-counts') },\n { id: 'stock-usage-audit', label: t('inventory.nav.usageAudit'), active: view === 'stock-usage-audit', onClick: () => navigate('stock-usage-audit') },\n { id: 'stock-history', label: t('inventory.nav.history'), active: view === 'stock-history', onClick: () => navigate('stock-history') },\n ],\n },\n ]\n\n if (config.modules.recipes) {\n items.push({\n id: 'recipes', label: config.labels.recipes, icon: 'BookOpen',\n children: [\n { id: 'recipes-list', label: config.labels.recipesList, active: view === 'recipes-list' || view.startsWith('recipes-detail:'), onClick: () => navigate('recipes-list') },\n { id: 'recipes-new', label: config.labels.recipesNew, active: view === 'recipes-new', onClick: () => navigate('recipes-new') },\n ],\n })\n }\n\n return items\n}\n\nexport function InventoryPage({ config, provider, store, registries }: {\n config: ResolvedInventoryConfig\n provider: InventoryDataProvider\n store: StoreApi<InventoryUIState>\n registries?: PluginRegistryDef[]\n}) {\n const t = useTranslation()\n const { view, direction, navigate } = useModuleNavigation('/inventory', {\n dashboard: 0,\n 'products-list': 0, 'products-new': 1, 'products-detail': 1,\n 'stock-entry': 1, 'stock-exit': 1, 'stock-history': 0, 'stock-counts': 0, 'stock-counts-new': 1,\n 'stock-usage-audit': 0,\n 'recipes-list': 0, 'recipes-new': 1, 'recipes-detail': 1,\n settings: 1,\n }, 'dashboard')\n\n const [onboardingComplete, setOnboardingComplete] = useState(() => {\n try { return localStorage.getItem('saas-core:inventory-onboarded') === 'true' } catch { return false }\n })\n\n const isSettings = view === 'settings'\n const isSummary = view === 'dashboard' || view === ''\n const nav = buildNav(config, view, navigate, t)\n\n const completeOnboarding = React.useCallback(async () => {\n await provider.ensureReferenceData?.()\n setOnboardingComplete(true)\n try { localStorage.setItem('saas-core:inventory-onboarded', 'true') } catch {}\n }, [provider])\n\n const quickActions = useMemo<PluginQuickAction[]>(() => {\n const actions: PluginQuickAction[] = [\n // Dropped with the catalogue module: offering \"new product\" while the\n // screen is gone would dead-end the user.\n ...(config.modules.products ? [{\n id: 'new-product',\n label: t('inventory.quickActions.newProduct'),\n icon: 'Package',\n description: t('inventory.quickActions.newProductDesc'),\n action: () => navigate('products-new'),\n } as PluginQuickAction] : []),\n {\n id: 'stock-entry',\n label: t('inventory.quickActions.stockEntry'),\n icon: 'ArrowUpRight',\n description: t('inventory.quickActions.stockEntryDesc'),\n action: () => navigate('stock-entry'),\n },\n {\n id: 'stock-exit',\n label: t('inventory.quickActions.stockExit'),\n icon: 'ArrowDownRight',\n description: t('inventory.quickActions.stockExitDesc'),\n action: () => navigate('stock-exit'),\n },\n ]\n return actions\n }, [])\n\n if (!onboardingComplete) {\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <InventoryOnboarding onComplete={completeOnboarding} />\n </InventoryContextProvider>\n )\n }\n\n if (isSettings && registries && registries.length > 0) {\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <PageTransition transitionKey=\"settings\" direction={direction}>\n <div style={{ padding: '24px' }}>\n <div style={{ marginBottom: '16px' }}>\n <h1 style={{ fontSize: '20px', fontWeight: 600, margin: 0 }}>{t('inventory.settingsPage.title')}</h1>\n <p style={{ color: 'var(--muted-foreground, #6b7280)', margin: '4px 0 0', fontSize: '14px' }}>\n {t('inventory.settingsPage.subtitle')}\n </p>\n </div>\n <PluginSettingsPanel\n title={t('inventory.settingsPage.title')}\n generalSettings={<InventoryGeneralSettings />}\n registries={registries}\n hostPluginId=\"inventory\"\n routeBase=\"/inventory/settings\"\n />\n </div>\n </PageTransition>\n </InventoryContextProvider>\n )\n }\n\n const renderView = createViewRouter([\n // Routes go with the module, not just the nav entry: leaving them mounted\n // keeps a second product form reachable by URL.\n ...(config.modules.products ? [\n { id: 'products', render: () => <ProductListView onNew={() => navigate('products-new')} onOpen={(id: string) => navigate(`products-detail:${id}`)} /> },\n { id: 'products-list', render: () => <ProductListView onNew={() => navigate('products-new')} onOpen={(id: string) => navigate(`products-detail:${id}`)} /> },\n { id: 'products-new', render: () => <ProductCrudForm onSaved={() => navigate('products-list')} /> },\n { id: 'products-edit', render: ({ id }: { id?: string }) => <ProductCrudForm editId={id!} onSaved={() => navigate(`products-detail:${id}`)} /> },\n { id: 'products-detail', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n // The tab writes `/products/<id>/stock` into the URL, so that link has to\n // come back to the same page with the tab open.\n { id: 'products-stock', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} initialTab=\"stock\" onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n ] : []),\n { id: 'stock-entry', render: () => <StockMovementView defaultType=\"entry\" onSaved={() => navigate('stock-history')} /> },\n { id: 'stock-exit', render: () => <StockMovementView defaultType=\"exit\" onSaved={() => navigate('stock-history')} /> },\n { id: 'stock-history', render: () => <MovementHistoryView onViewDetail={(id) => navigate(`stock-detail:${id}`)} onNew={() => navigate('stock-entry')} onNewExit={() => navigate('stock-exit')} /> },\n { id: 'stock-detail', render: ({ id }) => {\n const movement = store.getState().movements.find((m) => m.id === id)\n return movement\n ? <StockMovementView defaultType={movement.movementType} viewMovement={movement} onSaved={() => navigate('stock-history')} />\n : <MovementHistoryView onViewDetail={(mid) => navigate(`stock-detail:${mid}`)} />\n } },\n // One route id for both: `/inventory/stock/counts/<uuid>` parses back as\n // `stock-counts:<id>`, not `stock-counts-detail:<id>`.\n { id: 'stock-counts', render: ({ id }: { id?: string }) => id\n ? <StockCountSessionView sessionId={id} onBack={() => navigate('stock-counts')} />\n : <StockCountsView onNew={() => navigate('stock-counts-new')} onOpen={(sid) => navigate(`stock-counts:${sid}`)} /> },\n { id: 'stock-usage-audit', render: () => <UsageAuditView /> },\n { id: 'stock-counts-new', render: () => <StockCountFormView onOpened={(sid) => navigate(`stock-counts:${sid}`)} onCancel={() => navigate('stock-counts')} /> },\n { id: 'recipes', render: () => <RecipesView onNew={() => navigate('recipes-new')} onView={(id) => navigate(`recipes-detail:${id}`)} onNewForProduct={(pid) => navigate(`recipes-new:${pid}`)} /> },\n { id: 'recipes-list', render: () => <RecipesView onNew={() => navigate('recipes-new')} onView={(id) => navigate(`recipes-detail:${id}`)} onNewForProduct={(pid) => navigate(`recipes-new:${pid}`)} /> },\n { id: 'recipes-new', render: ({ id }: { id?: string }) => <RecipeFormView productId={id} onSaved={(rid) => rid ? navigate(`recipes-detail:${rid}`) : navigate('recipes-list')} /> },\n { id: 'recipes-detail', render: ({ id }) => <RecipeDetailView recipeId={id!} onBack={() => navigate('recipes-list')} /> },\n { id: 'dashboard', render: () => <DashboardView /> },\n ], 'dashboard')\n\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <ModulePage\n title={config.labels.pageTitle}\n subtitle={config.labels.pageSubtitle}\n nav={nav}\n showHeader={isSummary}\n viewKey={view}\n direction={direction}\n headerAction={\n <ModuleActionBar\n quickActions={quickActions}\n settingsPath={registries && registries.length > 0 ? '/settings/inventory' : undefined}\n />\n }\n >\n {renderView(view)}\n </ModulePage>\n </InventoryContextProvider>\n )\n}\n","import React, { useEffect } from 'react'\nimport { ArrowUpRight, ArrowDownRight } from 'lucide-react'\nimport type { StoreApi } from 'zustand'\nimport type { DashboardWidgetDef } from '@fayz-ai/core'\nimport { useTranslation } from '@fayz-ai/core'\nimport {\n KpiCard, Card, CardHeader, CardTitle, CardContent,\n defineKpiWidget, defineCustomWidget,\n} from '@fayz-ai/ui'\nimport { InventoryContextProvider, useInventoryConfig, useInventoryStore, formatCurrency, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '../data/types'\nimport type { InventoryUIState } from '../store'\n\nfunction useEnsureSummary() {\n const fetchSummary = useInventoryStore((s) => s.fetchSummary)\n useEffect(() => { void fetchSummary() }, [])\n}\n\nfunction StockValueKpi() {\n const t = useTranslation()\n const { currency } = useInventoryConfig()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return (\n <KpiCard label={t('inventory.dashboard.stockValue')} icon=\"BarChart3\"\n value={formatCurrency(summary?.totalStockValue ?? 0, currency)} sub={t('inventory.dashboard.totalValue')} />\n )\n}\n\nfunction TotalProductsKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.totalProducts')} icon=\"Package\" value={String(summary?.totalProducts ?? 0)} sub={t('inventory.dashboard.activeItems')} />\n}\n\nfunction LowStockKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.lowStock')} icon=\"AlertTriangle\" value={String(summary?.lowStockCount ?? 0)} sub={t('inventory.dashboard.belowMinimum')} />\n}\n\nfunction OutOfStockKpi() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return <KpiCard label={t('inventory.dashboard.outOfStock')} icon=\"TrendingDown\" value={String(summary?.outOfStockCount ?? 0)} sub={t('inventory.dashboard.needRestocking')} />\n}\n\nfunction RecentActivityPanel() {\n const t = useTranslation()\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n return (\n <Card>\n <CardHeader><CardTitle>{t('inventory.dashboard.recentActivity')}</CardTitle></CardHeader>\n <CardContent>\n <div className=\"flex items-center gap-4 text-sm\">\n <div className=\"flex items-center gap-1.5\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-success\" />\n <span className=\"text-muted-foreground\">{t('inventory.dashboard.entries')}</span>\n <span className=\"font-medium\">{summary?.movementsByType?.entry ?? 0}</span>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <ArrowDownRight className=\"h-3.5 w-3.5 text-destructive\" />\n <span className=\"text-muted-foreground\">{t('inventory.dashboard.exits')}</span>\n <span className=\"font-medium\">{summary?.movementsByType?.exit ?? 0}</span>\n </div>\n </div>\n <p className=\"mt-2 text-xs text-muted-foreground\">{t('inventory.dashboard.last7Days')}</p>\n </CardContent>\n </Card>\n )\n}\n\nexport function createInventoryDashboardWidgets(ctx: {\n config: ResolvedInventoryConfig\n provider: InventoryDataProvider\n store: StoreApi<InventoryUIState>\n}): DashboardWidgetDef[] {\n const withCtx = (Inner: React.ComponentType): React.ComponentType<unknown> => {\n const Wrapped = () => (\n <InventoryContextProvider config={ctx.config} provider={ctx.provider} store={ctx.store}>\n <Inner />\n </InventoryContextProvider>\n )\n Wrapped.displayName = `InventoryWidget(${Inner.displayName ?? Inner.name})`\n return Wrapped\n }\n\n return [\n // Stock value is inventory's headline KPI on the global home; the rest are\n // home-hidden by default (shown on the inventory plugin-home, addable via Customize).\n defineKpiWidget({ id: 'inventory.kpi.stock-value', title: 'inventory.dashboard.stockValue', domain: 'inventory', defaultOrder: 0, component: withCtx(StockValueKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.total-products', title: 'inventory.dashboard.totalProducts', domain: 'inventory', defaultOrder: 1, defaultVisible: false, component: withCtx(TotalProductsKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.low-stock', title: 'inventory.dashboard.lowStock', domain: 'inventory', defaultOrder: 2, defaultVisible: false, component: withCtx(LowStockKpi) }),\n defineKpiWidget({ id: 'inventory.kpi.out-of-stock', title: 'inventory.dashboard.outOfStock', domain: 'inventory', defaultOrder: 3, defaultVisible: false, component: withCtx(OutOfStockKpi) }),\n defineCustomWidget({ id: 'inventory.panel.recent-activity', title: 'inventory.dashboard.recentActivity', domain: 'inventory', span: 2, defaultOrder: 10, surfaces: ['plugin-home'], component: withCtx(RecentActivityPanel) }),\n ]\n}\n","import type { InventoryDataProvider } from './types'\nimport type {\n Product, StockMovement, StockPosition, StockLocation, Supplier,\n Recipe, RecipeIngredient, RecipeGroup,\n StockCountSession, StockCountItem, ProductCategory,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput, CreateRecipeIngredientInput,\n OpenStockCountInput, CloseStockCountResult,\n ProductQuery, MovementQuery, UsageAuditQuery, UsageAuditEntry, UsageAuditBatchResult,\n PaginatedResult, InventorySummary, MovementType,\n ConsumeRecipeForSourceInput, ReverseRecipeConsumptionInput, InventoryConsumptionResult,\n} from '../types'\nimport { isDivergent } from '../lib/stock-count'\n\nlet nextId = 1\nfunction uid(): string { return String(nextId++) }\nfunction now(): string { return new Date().toISOString() }\nfunction today(): string { return new Date().toISOString().slice(0, 10) }\n\nfunction paginate<T>(items: T[], page?: number, pageSize?: number): PaginatedResult<T> {\n const p = page ?? 1\n const ps = pageSize ?? 50\n const start = (p - 1) * ps\n return { data: items.slice(start, start + ps), total: items.length }\n}\n\ninterface MockStore {\n products: Product[]\n movements: StockMovement[]\n positions: StockPosition[]\n locations: StockLocation[]\n suppliers: Supplier[]\n recipes: Recipe[]\n recipeIngredients: RecipeIngredient[]\n recipeGroups: RecipeGroup[]\n countSessions: StockCountSession[]\n countItems: StockCountItem[]\n consumptions: Map<string, {\n result: InventoryConsumptionResult\n movementIds: string[]\n }>\n}\n\nfunction createStore(): MockStore {\n return {\n products: [],\n movements: [],\n positions: [],\n locations: [\n { id: uid(), name: 'Main Storage', description: 'Primary storage area', isActive: true, tenantId: 'mock-tenant', createdAt: now(), updatedAt: now() },\n ],\n suppliers: [\n { id: uid(), name: 'Main Supplier' },\n ],\n recipes: [],\n recipeIngredients: [],\n recipeGroups: [],\n countSessions: [],\n countItems: [],\n consumptions: new Map(),\n }\n}\n\nexport function createMockInventoryProvider(): InventoryDataProvider {\n const store = createStore()\n const tenantId = 'mock-tenant'\n\n /** The produced product's name and price, as the Supabase embed resolves them. */\n function withProduct(recipe: Recipe): Recipe {\n const product = store.products.find((p) => p.id === recipe.productId)\n return { ...recipe, productName: product?.name ?? recipe.productName, productSalePrice: product?.salePrice }\n }\n\n function withCostBasis(ing: RecipeIngredient): RecipeIngredient {\n const product = store.products.find((p) => p.id === ing.productId)\n if (!product) return ing\n return {\n ...ing,\n productName: product.name ?? ing.productName,\n costBasis: {\n cost: product.costPrice ?? 0,\n conversionFactor: product.conversionFactor,\n purchaseUnitId: product.purchaseUnitId,\n },\n }\n }\n\n /** Same slot key the Supabase provider uses: product + location + batch + expiry. */\n /** Mirrors the supabase provider: `set` makes the slot BE `amount`. Returns the effective delta. */\n function applyPositionDelta(\n input: Pick<CreateStockMovementInput, 'productId' | 'unitCost' | 'batchNumber' | 'expirationDate'>,\n locationId: string,\n amount: number,\n mode: 'add' | 'set' = 'add',\n ): number {\n const slot = store.positions.find((p) =>\n p.productId === input.productId &&\n p.stockLocationId === locationId &&\n (p.batchNumber ?? null) === (input.batchNumber ?? null) &&\n (p.expirationDate ?? null) === (input.expirationDate ?? null)\n )\n if (slot) {\n const current = slot.quantity\n slot.quantity = mode === 'set' ? amount : current + amount\n slot.unitCost = input.unitCost ?? slot.unitCost\n slot.updatedAt = now()\n return slot.quantity - current\n }\n store.positions.push({\n id: uid(),\n productId: input.productId,\n quantity: amount,\n unitCost: input.unitCost ?? 0,\n stockLocationId: locationId,\n stockLocationName: store.locations.find((l) => l.id === locationId)?.name,\n batchNumber: input.batchNumber,\n expirationDate: input.expirationDate,\n tenantId,\n createdAt: now(),\n })\n return amount\n }\n\n const provider: InventoryDataProvider = {\n async ensureReferenceData(): Promise<void> {\n // The mock store is born with its reference data already available.\n },\n\n // --- Products ---\n async getProducts(query: ProductQuery): Promise<PaginatedResult<Product>> {\n let results = [...store.products]\n if (query.productType) results = results.filter((p) => p.productType === query.productType)\n if (query.categoryId) results = results.filter((p) => p.categoryId === query.categoryId)\n if (query.isActive !== undefined) results = results.filter((p) => p.isActive === query.isActive)\n if (query.lowStockOnly) results = results.filter((p) => p.currentQuantity <= p.minQuantity)\n if (query.search) {\n const s = query.search.toLowerCase()\n results = results.filter((p) => p.name.toLowerCase().includes(s) || p.sku?.toLowerCase().includes(s) || p.barcode?.includes(s))\n }\n results.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n return paginate(results, query.page, query.pageSize)\n },\n\n async getProductById(id: string): Promise<Product | null> {\n return store.products.find((p) => p.id === id) ?? null\n },\n\n async createProduct(input: CreateProductInput): Promise<Product> {\n const product: Product = {\n id: uid(),\n name: input.name,\n description: input.description,\n sku: input.sku,\n barcode: input.barcode,\n brand: input.brand,\n categoryId: input.categoryId,\n productType: input.productType,\n purpose: input.purpose,\n currentQuantity: 0,\n minQuantity: input.minQuantity ?? 0,\n maxQuantity: input.maxQuantity,\n costPrice: input.costPrice ?? 0,\n salePrice: input.salePrice,\n measurementUnitId: input.measurementUnitId,\n purchaseUnitId: input.purchaseUnitId,\n conversionFactor: input.conversionFactor ?? 1,\n isActive: true,\n supplierId: input.supplierId,\n defaultLocationId: input.defaultLocationId,\n imageUrl: input.imageUrl,\n metadata: input.metadata,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.products.push(product)\n return product\n },\n\n async updateProduct(id: string, data: Partial<Product>): Promise<Product> {\n const product = store.products.find((p) => p.id === id)\n if (!product) throw new Error(`Product ${id} not found`)\n Object.assign(product, data, { updatedAt: now() })\n return product\n },\n\n async uploadProductImage(productId: string, file: File): Promise<string> {\n const product = store.products.find((p) => p.id === productId)\n if (!product) throw new Error(`Product ${productId} not found`)\n const url = typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'\n ? URL.createObjectURL(file)\n : `mock://inventory-images/${tenantId}/products/${productId}/${encodeURIComponent(file.name)}`\n product.imageUrl = url\n product.updatedAt = now()\n return url\n },\n\n // --- Stock Movements ---\n async getMovements(query: MovementQuery): Promise<PaginatedResult<StockMovement>> {\n let results = [...store.movements]\n if (query.productId) results = results.filter((m) => m.productId === query.productId)\n if (query.movementType) {\n const types = Array.isArray(query.movementType) ? query.movementType : [query.movementType]\n results = results.filter((m) => types.includes(m.movementType))\n }\n if (query.stockLocationId) results = results.filter((m) => m.stockLocationId === query.stockLocationId)\n if (query.dateRange) {\n results = results.filter((m) => m.movementDate >= query.dateRange!.from && m.movementDate <= query.dateRange!.to)\n }\n if (query.search) {\n const s = query.search.toLowerCase()\n results = results.filter((m) => m.productName?.toLowerCase().includes(s) || m.notes?.toLowerCase().includes(s))\n }\n results.sort((a, b) => b.movementDate.localeCompare(a.movementDate))\n return paginate(results, query.page, query.pageSize)\n },\n\n async createMovement(input: CreateStockMovementInput): Promise<StockMovement> {\n const product = store.products.find((p) => p.id === input.productId)\n const location = input.stockLocationId ? store.locations.find((l) => l.id === input.stockLocationId) : undefined\n const unitCost = input.unitCost ?? product?.costPrice ?? 0\n\n const movement: StockMovement = {\n id: uid(),\n productId: input.productId,\n productName: product?.name,\n quantity: input.quantity,\n movementType: input.movementType,\n unitCost,\n totalCost: unitCost * input.quantity,\n stockLocationId: input.stockLocationId,\n stockLocationName: location?.name,\n destinationLocationId: input.destinationLocationId,\n supplierId: input.supplierId,\n supplierName: store.suppliers.find((s) => s.id === input.supplierId)?.name,\n documentNumber: input.documentNumber,\n reason: input.reason,\n notes: input.notes,\n batchNumber: input.batchNumber,\n expirationDate: input.expirationDate,\n movementDate: input.movementDate ?? today(),\n tenantId,\n createdAt: now(),\n }\n store.movements.push(movement)\n\n let stockDelta =\n input.movementType === 'entry' ? input.quantity\n : input.movementType === 'exit' || input.movementType === 'loss' ? -input.quantity\n : 0\n\n if (input.stockLocationId) {\n const slot = { ...input, unitCost }\n // `adjustment` declares effect 'set': the quantity is the counted truth,\n // not a delta. It used to be subtracted like an exit.\n const mode = input.movementType === 'adjustment' ? 'set' : 'add'\n const amount = mode === 'set'\n ? input.quantity\n : (input.movementType === 'entry' ? input.quantity : -input.quantity)\n const applied = applyPositionDelta(slot, input.stockLocationId, amount, mode)\n if (input.movementType === 'adjustment') stockDelta = applied\n\n if (input.movementType === 'transfer' && input.destinationLocationId) {\n applyPositionDelta(slot, input.destinationLocationId, input.quantity)\n stockDelta = 0\n }\n } else if (input.movementType === 'adjustment') {\n stockDelta = input.quantity - (product?.currentQuantity ?? 0)\n }\n\n if (product) {\n product.currentQuantity += stockDelta\n product.updatedAt = now()\n }\n\n return movement\n },\n\n async reverseMovement(movementId: string): Promise<void> {\n const index = store.movements.findIndex((m) => m.id === movementId)\n if (index === -1) throw new Error(`Movement ${movementId} not found`)\n const movement = store.movements[index]\n\n const product = store.products.find((p) => p.id === movement.productId)\n if (product) {\n if (movement.movementType === 'entry') product.currentQuantity -= movement.quantity\n else if (movement.movementType === 'exit' || movement.movementType === 'loss') product.currentQuantity += movement.quantity\n product.updatedAt = now()\n }\n\n if (movement.stockLocationId) {\n const slot = {\n productId: movement.productId,\n unitCost: movement.unitCost,\n batchNumber: movement.batchNumber,\n expirationDate: movement.expirationDate,\n }\n applyPositionDelta(slot, movement.stockLocationId, movement.movementType === 'entry' ? -movement.quantity : movement.quantity)\n if (movement.movementType === 'transfer' && movement.destinationLocationId) {\n applyPositionDelta(slot, movement.destinationLocationId, -movement.quantity)\n }\n }\n\n store.movements.splice(index, 1)\n },\n\n // --- Usage audit ---\n // The mock has no sold lines, so there is nothing consumed to confer. An\n // empty queue is the honest answer here, not invented divergences.\n async getUsageAudit(_query: UsageAuditQuery): Promise<PaginatedResult<UsageAuditEntry>> {\n return { data: [], total: 0 }\n },\n\n async correctUsage(): Promise<void> {\n throw new Error('Usage corrections need the ledger; the mock provider has none')\n },\n\n async correctUsageBatch(): Promise<UsageAuditBatchResult> {\n throw new Error('Usage corrections need the ledger; the mock provider has none')\n },\n\n // --- Stock Positions ---\n async getPositions(productId: string): Promise<StockPosition[]> {\n return store.positions.filter((p) => p.productId === productId)\n },\n\n // --- Stock Locations ---\n async getLocations(): Promise<StockLocation[]> {\n return store.locations.filter((l) => l.isActive)\n },\n\n async createLocation(data): Promise<StockLocation> {\n const location: StockLocation = {\n id: uid(),\n name: data.name,\n description: data.description,\n isActive: true,\n unitId: data.unitId,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.locations.push(location)\n return location\n },\n\n // --- Suppliers ---\n async getSuppliers(): Promise<Supplier[]> {\n return store.suppliers\n },\n\n // --- Categories ---\n async getCategories(): Promise<ProductCategory[]> {\n const seen = new Map<string, ProductCategory>()\n for (const product of store.products) {\n if (!product.categoryId || seen.has(product.categoryId)) continue\n seen.set(product.categoryId, {\n id: product.categoryId,\n name: product.categoryName ?? product.categoryId,\n isActive: true,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n })\n }\n return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name))\n },\n\n // --- Stock counts ---\n async getCountSessions(): Promise<StockCountSession[]> {\n return [...store.countSessions]\n .sort((a, b) => b.openedAt.localeCompare(a.openedAt))\n .map((session) => {\n const items = store.countItems.filter((i) => i.sessionId === session.id)\n return {\n ...session,\n itemCount: items.length,\n countedCount: items.filter((i) => i.countedQuantity !== undefined).length,\n divergentCount: items.filter(isDivergent).length,\n }\n })\n },\n\n async getCountSession(id: string): Promise<StockCountSession | null> {\n return store.countSessions.find((s) => s.id === id) ?? null\n },\n\n async getCountItems(sessionId: string): Promise<StockCountItem[]> {\n return store.countItems\n .filter((i) => i.sessionId === sessionId)\n .sort((a, b) => (a.productName ?? '').localeCompare(b.productName ?? ''))\n },\n\n async openCountSession(input: OpenStockCountInput): Promise<StockCountSession> {\n const location = store.locations.find((l) => l.id === input.stockLocationId)\n if (!location) throw new Error(`Stock location ${input.stockLocationId} not found`)\n\n const session: StockCountSession = {\n id: uid(),\n reference: input.reference?.trim() || undefined,\n status: 'open',\n stockLocationId: input.stockLocationId,\n stockLocationName: location.name,\n categoryId: input.categoryId,\n blind: input.blind ?? true,\n notes: input.notes,\n openedAt: now(),\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n store.countSessions.push(session)\n\n // Snapshot AT OPEN: what the system believes now, frozen on the line.\n for (const product of store.products) {\n if (!product.isActive || product.productType === 'asset') continue\n if (input.categoryId && product.categoryId !== input.categoryId) continue\n const slots = store.positions.filter(\n (p) => p.productId === product.id && p.stockLocationId === input.stockLocationId,\n )\n store.countItems.push({\n id: uid(),\n sessionId: session.id,\n productId: product.id,\n productName: product.name,\n productSku: product.sku,\n systemQuantity: slots.reduce((sum, p) => sum + (p.quantity ?? 0), 0),\n unitCost: slots[0]?.unitCost ?? product.costPrice ?? 0,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n })\n }\n return session\n },\n\n async saveCountEntry(itemId: string, quantity: number | null, notes?: string): Promise<StockCountItem> {\n const item = store.countItems.find((i) => i.id === itemId)\n if (!item) throw new Error(`Count item ${itemId} not found`)\n item.countedQuantity = quantity == null ? undefined : quantity\n item.countedAt = quantity == null ? undefined : now()\n if (notes !== undefined) item.notes = notes || undefined\n item.updatedAt = now()\n\n const session = store.countSessions.find((s) => s.id === item.sessionId)\n if (session && session.status === 'open') session.status = 'counting'\n return item\n },\n\n async closeCountSession(sessionId: string, reason?: string): Promise<CloseStockCountResult> {\n const session = store.countSessions.find((s) => s.id === sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n if (session.status === 'closed') {\n return { sessionId, adjustmentsCreated: 0, alreadyClosed: true }\n }\n if (session.status === 'cancelled') throw new Error('This count was cancelled')\n\n let emitted = 0\n for (const item of store.countItems) {\n if (item.sessionId !== sessionId) continue\n // Uncounted lines and lines that already adjusted are both skipped.\n if (!isDivergent(item) || item.movementId) continue\n const counted = item.countedQuantity as number\n const delta = counted - item.systemQuantity\n\n const movement: StockMovement = {\n id: uid(),\n productId: item.productId,\n productName: item.productName,\n quantity: counted,\n movementType: 'adjustment',\n unitCost: item.unitCost,\n totalCost: item.unitCost * counted,\n stockLocationId: session.stockLocationId,\n stockLocationName: session.stockLocationName,\n reason: reason || 'Stock count',\n movementDate: today(),\n metadata: {\n countSessionId: sessionId,\n countItemId: item.id,\n systemQuantity: item.systemQuantity,\n countedQuantity: counted,\n variance: delta,\n },\n tenantId,\n createdAt: now(),\n }\n store.movements.push(movement)\n item.movementId = movement.id\n item.updatedAt = now()\n\n applyPositionDelta({ productId: item.productId, unitCost: item.unitCost }, session.stockLocationId, delta)\n const product = store.products.find((p) => p.id === item.productId)\n if (product) {\n product.currentQuantity += delta\n product.updatedAt = now()\n }\n emitted += 1\n }\n\n session.status = 'closed'\n session.closedAt = now()\n session.updatedAt = now()\n return { sessionId, adjustmentsCreated: emitted, alreadyClosed: false }\n },\n\n async cancelCountSession(sessionId: string): Promise<StockCountSession> {\n const session = store.countSessions.find((s) => s.id === sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n if (session.status === 'closed') throw new Error('A closed count cannot be cancelled')\n session.status = 'cancelled'\n session.updatedAt = now()\n return session\n },\n\n // --- Recipes ---\n async getRecipes(): Promise<Recipe[]> {\n return store.recipes.filter((r) => r.isActive).map(withProduct)\n },\n\n async getRecipeById(id: string): Promise<Recipe | null> {\n const recipe = store.recipes.find((r) => r.id === id)\n return recipe ? withProduct(recipe) : null\n },\n\n async getRecipeIngredients(recipeId: string): Promise<RecipeIngredient[]> {\n return store.recipeIngredients\n .filter((ri) => ri.recipeId === recipeId)\n .sort((a, b) => a.displayOrder - b.displayOrder)\n .map(withCostBasis)\n },\n\n async getAllRecipeIngredients(): Promise<RecipeIngredient[]> {\n return store.recipeIngredients.map(withCostBasis)\n },\n\n async getRecipeGroups(recipeId: string): Promise<RecipeGroup[]> {\n return store.recipeGroups.filter((g) => g.recipeId === recipeId).sort((a, b) => a.displayOrder - b.displayOrder)\n },\n\n async createRecipe(input: CreateRecipeInput): Promise<Recipe> {\n const product = store.products.find((p) => p.id === input.productId)\n const recipeId = uid()\n const recipe: Recipe = {\n id: recipeId,\n name: input.name,\n description: input.description,\n productId: input.productId,\n productName: product?.name,\n yieldQuantity: input.yieldQuantity,\n yieldUnitId: input.yieldUnitId,\n preparationTimeMinutes: input.preparationTimeMinutes,\n instructions: input.instructions,\n isActive: true,\n ingredientCount: input.ingredients.length,\n tenantId,\n createdAt: now(),\n updatedAt: now(),\n }\n // One active ficha per product. Re-saving used to leave the previous one\n // active too, and `consumeRecipeForSource` picks a single active recipe —\n // so a stale duplicate could be the one deciding a stock movement.\n for (const existing of store.recipes) {\n if (existing.id !== recipeId && existing.productId === input.productId && existing.isActive) {\n existing.isActive = false\n existing.updatedAt = now()\n }\n }\n store.recipes.push(recipe)\n\n for (const ing of input.ingredients) {\n const ingProduct = store.products.find((p) => p.id === ing.productId)\n store.recipeIngredients.push({\n id: uid(),\n recipeId,\n productId: ing.productId,\n productName: ingProduct?.name,\n quantity: ing.quantity,\n unitId: ing.unitId,\n displayOrder: ing.displayOrder ?? 0,\n notes: ing.notes,\n createdAt: now(),\n })\n }\n\n return recipe\n },\n\n async updateRecipe(id: string, patch: Partial<Recipe>): Promise<Recipe> {\n const recipe = store.recipes.find((r) => r.id === id)\n if (!recipe) throw new Error(`Recipe ${id} not found`)\n Object.assign(recipe, patch, { updatedAt: now() })\n return withProduct(recipe)\n },\n\n async addRecipeIngredient(recipeId: string, input: CreateRecipeIngredientInput): Promise<RecipeIngredient> {\n const product = store.products.find((p) => p.id === input.productId)\n const ingredient: RecipeIngredient = {\n id: uid(),\n recipeId,\n productId: input.productId,\n productName: product?.name,\n quantity: input.quantity,\n unitId: input.unitId,\n displayOrder: input.displayOrder ?? store.recipeIngredients.filter((i) => i.recipeId === recipeId).length,\n notes: input.notes,\n createdAt: now(),\n }\n store.recipeIngredients.push(ingredient)\n const recipe = store.recipes.find((r) => r.id === recipeId)\n if (recipe) recipe.ingredientCount = store.recipeIngredients.filter((i) => i.recipeId === recipeId).length\n return withCostBasis(ingredient)\n },\n\n async consumeRecipeForSource(input: ConsumeRecipeForSourceInput): Promise<InventoryConsumptionResult> {\n const sourceType = input.sourceType.trim()\n const sourceId = input.sourceId.trim()\n if (!sourceType || !sourceId) throw new Error('Inventory consumption requires a source type and id')\n if (!Number.isFinite(input.quantity) || input.quantity <= 0) {\n throw new Error('Inventory consumption quantity must be positive')\n }\n\n const idempotencyKey = `${sourceType}:${sourceId}`\n const replay = store.consumptions.get(idempotencyKey)\n if (replay) return replay.result\n\n const recipe = store.recipes\n .filter((item) => item.productId === input.productId && item.isActive)\n .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))[0]\n if (!recipe) {\n return {\n sourceType,\n sourceId,\n idempotencyKey,\n status: 'skipped',\n lineCount: 0,\n skipReason: 'no_active_recipe',\n }\n }\n if (!Number.isFinite(recipe.yieldQuantity) || recipe.yieldQuantity <= 0) {\n throw new Error(`Recipe ${recipe.id} has an invalid yield quantity`)\n }\n\n const ingredients = store.recipeIngredients.filter((item) => item.recipeId === recipe.id)\n if (!ingredients.length) throw new Error(`Recipe ${recipe.id} has no ingredients`)\n const factor = input.quantity / recipe.yieldQuantity\n const lines = new Map<string, { product: Product; locationId: string; quantity: number }>()\n for (const ingredient of ingredients) {\n const product = store.products.find((item) => item.id === ingredient.productId)\n if (!product) throw new Error(`Ingredient ${ingredient.productId} was not found`)\n if (!product.defaultLocationId) {\n throw new Error(`Ingredient ${ingredient.productId} has no default stock location`)\n }\n const quantity = Math.round(ingredient.quantity * factor * 10_000) / 10_000\n if (!Number.isFinite(quantity) || quantity <= 0) {\n throw new Error(`Recipe ${recipe.id} produced an invalid quantity for ingredient ${ingredient.productId}`)\n }\n const lineKey = `${product.id}:${product.defaultLocationId}`\n const current = lines.get(lineKey)\n if (current) current.quantity = Math.round((current.quantity + quantity) * 10_000) / 10_000\n else lines.set(lineKey, { product, locationId: product.defaultLocationId, quantity })\n }\n\n for (const line of lines.values()) {\n const position = store.positions.find((item) =>\n item.productId === line.product.id && item.stockLocationId === line.locationId)\n if ((position?.quantity ?? 0) < line.quantity) {\n throw new Error(`Insufficient stock for ingredient ${line.product.name}`)\n }\n }\n\n const movementIds: string[] = []\n for (const line of lines.values()) {\n const movement = await provider.createMovement({\n productId: line.product.id,\n quantity: line.quantity,\n movementType: 'exit',\n stockLocationId: line.locationId,\n reason: `Recipe ${recipe.id}`,\n notes: idempotencyKey,\n })\n movementIds.push(movement.id)\n }\n const result: InventoryConsumptionResult = {\n sourceType,\n sourceId,\n idempotencyKey,\n status: 'confirmed',\n recipeId: recipe.id,\n lineCount: lines.size,\n }\n store.consumptions.set(idempotencyKey, { result, movementIds })\n return result\n },\n\n async reverseRecipeConsumption(input: ReverseRecipeConsumptionInput): Promise<InventoryConsumptionResult> {\n const sourceType = input.sourceType.trim()\n const sourceId = input.sourceId.trim()\n if (!sourceType || !sourceId) throw new Error('Inventory consumption requires a source type and id')\n if (!input.reason.trim()) throw new Error('Inventory consumption reversal requires a reason')\n\n const idempotencyKey = `${sourceType}:${sourceId}`\n const consumption = store.consumptions.get(idempotencyKey)\n if (!consumption) {\n return {\n sourceType,\n sourceId,\n idempotencyKey,\n status: 'skipped',\n lineCount: 0,\n skipReason: 'nothing_to_reverse',\n }\n }\n if (consumption.result.status === 'reversed') return consumption.result\n\n for (const movementId of consumption.movementIds) {\n await provider.reverseMovement(movementId)\n }\n const result: InventoryConsumptionResult = {\n ...consumption.result,\n status: 'reversed',\n }\n store.consumptions.set(idempotencyKey, { result, movementIds: [] })\n return result\n },\n\n // --- Summary ---\n async getSummary(): Promise<InventorySummary> {\n const active = store.products.filter((p) => p.isActive)\n const lowStock = active.filter((p) => p.currentQuantity <= p.minQuantity && p.currentQuantity > 0)\n const outOfStock = active.filter((p) => p.currentQuantity <= 0)\n const totalValue = active.reduce((sum, p) => sum + p.currentQuantity * p.costPrice, 0)\n\n const weekAgo = new Date()\n weekAgo.setDate(weekAgo.getDate() - 7)\n const weekAgoStr = weekAgo.toISOString().slice(0, 10)\n const recent = store.movements.filter((m) => m.movementDate >= weekAgoStr)\n\n const movementsByType: Record<MovementType, number> = { entry: 0, exit: 0, adjustment: 0, transfer: 0, loss: 0 }\n for (const m of recent) movementsByType[m.movementType]++\n\n return {\n totalProducts: active.length,\n lowStockCount: lowStock.length,\n outOfStockCount: outOfStock.length,\n totalStockValue: totalValue,\n recentMovementCount: recent.length,\n movementsByType,\n }\n },\n }\n\n return provider\n}\n","export const DEFAULT_MEASUREMENT_UNITS = [\n { name: 'Unit', abbreviation: 'un' },\n { name: 'Box', abbreviation: 'box' },\n { name: 'Kilogram', abbreviation: 'kg' },\n { name: 'Gram', abbreviation: 'g' },\n { name: 'Liter', abbreviation: 'L' },\n { name: 'Milliliter', abbreviation: 'mL' },\n] as const\n\nexport const DEFAULT_STOCK_LOCATION = {\n name: 'Main Storage',\n description: 'Primary storage area',\n} as const\n\nexport function getMissingMeasurementUnits(\n rows: Array<{ abbreviation?: string | null }>,\n): typeof DEFAULT_MEASUREMENT_UNITS[number][] {\n const existing = new Set(\n rows.map((row) => String(row.abbreviation ?? '').trim().toLocaleLowerCase()),\n )\n return DEFAULT_MEASUREMENT_UNITS.filter(\n (unit) => !existing.has(unit.abbreviation.toLocaleLowerCase()),\n )\n}\n\nexport function getDuplicateDefaultUnitIds(\n rows: Array<{ id: string; abbreviation?: string | null; created_at?: string | null }>,\n): string[] {\n const defaults = new Set(\n DEFAULT_MEASUREMENT_UNITS.map((unit) => unit.abbreviation.toLocaleLowerCase()),\n )\n const firstByAbbreviation = new Map<string, number>()\n const duplicates: string[] = []\n\n for (const row of [...rows].sort((a, b) =>\n String(a.created_at ?? '').localeCompare(String(b.created_at ?? '')) || a.id.localeCompare(b.id),\n )) {\n const abbreviation = String(row.abbreviation ?? '').trim().toLocaleLowerCase()\n if (!defaults.has(abbreviation)) continue\n const createdAt = row.created_at ? Date.parse(row.created_at) : Number.NaN\n const firstAt = firstByAbbreviation.get(abbreviation)\n if (firstAt === undefined) {\n if (Number.isFinite(createdAt)) firstByAbbreviation.set(abbreviation, createdAt)\n continue\n }\n // Delete only the near-simultaneous copy created by the former StrictMode\n // race. A same-abbreviation unit created independently later is user data.\n if (Number.isFinite(createdAt) && Math.abs(createdAt - firstAt) <= 60_000) duplicates.push(row.id)\n }\n\n return duplicates\n}\n\nexport function getDuplicateAutoCreatedLocationIds(\n rows: Array<{ id: string; name?: string | null; created_at?: string | null }>,\n): string[] {\n const defaults = rows\n .filter((row) => row.name === DEFAULT_STOCK_LOCATION.name && row.created_at)\n .sort((a, b) => String(a.created_at).localeCompare(String(b.created_at)) || a.id.localeCompare(b.id))\n const first = defaults[0]\n if (!first?.created_at) return []\n const firstAt = Date.parse(first.created_at)\n\n // Only collapse the near-simultaneous copies produced by the former\n // StrictMode race. Locations created independently at another time remain.\n return defaults.slice(1)\n .filter((row) => Math.abs(Date.parse(String(row.created_at)) - firstAt) <= 60_000)\n .map((row) => row.id)\n}\n","import type { InventoryDataProvider } from './types'\nimport type {\n Product, StockMovement, StockPosition, StockLocation, Supplier,\n Recipe, RecipeIngredient, RecipeGroup,\n StockCountSession, StockCountItem, ProductCategory,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput, CreateRecipeIngredientInput,\n OpenStockCountInput, CloseStockCountResult,\n ProductQuery, MovementQuery, UsageAuditQuery, UsageAuditEntry,\n UsageAuditCorrection, UsageAuditBatchResult,\n PaginatedResult, InventorySummary, MovementType,\n ConsumeRecipeForSourceInput, ReverseRecipeConsumptionInput, InventoryConsumptionResult,\n} from '../types'\nimport { getSupabaseClientOptional, getActiveTenantId, getActiveUnitId } from '@fayz-ai/core'\nimport { getInventoryTenantId } from '../lib/tenant'\nimport { T } from './tables'\nimport {\n DEFAULT_STOCK_LOCATION,\n getDuplicateAutoCreatedLocationIds,\n getDuplicateDefaultUnitIds,\n getMissingMeasurementUnits,\n} from './reference-data'\n\nconst referenceDataPromises = new Map<string, Promise<void>>()\n\nfunction getTenantId(): string | undefined {\n // Local override wins; else use the app's active tenant so writes pass RLS.\n return getInventoryTenantId() ?? getActiveTenantId()\n}\n\nfunction snakeToCamel(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n const camelKey = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())\n result[camelKey] = value\n }\n return result\n}\n\nfunction camelToSnake(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj)) {\n if (key.startsWith('_')) continue\n const snakeKey = key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`)\n result[snakeKey] = value\n }\n return result\n}\n\n/** Embed alias for the 005 satellite — one round trip instead of an N+1. */\nconst PRODUCT_SELECT = `*, ${T.productDetails}(*)`\n/**\n * The catalogue as this plugin reads it. `products` no longer carries a balance\n * (spine 188); v_inventory_products is the same row with `stock`, `available`,\n * `reserved` and `min_stock` derived from the ledger and the product settings.\n * Writes still address `products` — a view is what you read, not what you own.\n */\nconst PRODUCTS_READ = 'v_inventory_products'\n\n/** The consumption the sales already posted, next to the recipe standard (001). */\nconst USAGE_AUDIT_READ = 'v_inventory_usage_audit'\n\n/** The tenant's own stock location, for a screen that did not name one. */\nasync function defaultLocationId(pub: any, tenantId: string | undefined): Promise<string | undefined> {\n if (!tenantId) return undefined\n const { data } = await pub\n .from('plg_inventory_stock_locations')\n .select('id')\n .eq('tenant_id', tenantId)\n .eq('is_active', true)\n .order('created_at')\n .limit(1)\n return data?.[0]?.id\n}\n\n/**\n * The UI's verb → the ledger's `kind`.\n *\n * Two vocabularies for one idea, and the CHECK constraint is the one that has\n * to be satisfied: `kind` is in/out/transfer/adjust/reverse, while the screen\n * (and MovementType) says entry/exit/adjustment. `loss` has no kind of its own\n * — it is an adjustment whose reason says what happened, which is exactly what\n * the reason column is for.\n */\nconst LEDGER_KIND: Readonly<Record<string, string>> = {\n entry: 'in',\n exit: 'out',\n transfer: 'transfer',\n adjustment: 'adjust',\n loss: 'adjust',\n}\n\nfunction supabaseError(operation: string, error: { message?: string } | null | undefined): void {\n if (error) throw new Error(`${operation}: ${error.message ?? 'Supabase request failed'}`)\n}\n\n/**\n * Hydrate recipe products explicitly instead of relying on a PostgREST embed.\n *\n * Pools can briefly have a stale relationship cache after plugin migrations,\n * and an embedded `products(...)` select then makes the whole recipe query\n * fail. The old provider discarded that error and returned an empty list,\n * which looked exactly like a recipe that vanished after save.\n */\nasync function hydrateRecipeRows(pub: any, rows: Record<string, any>[]): Promise<Recipe[]> {\n const productIds = [...new Set(rows.map((row) => row.product_id).filter(Boolean))]\n const productsById = new Map<string, Record<string, any>>()\n if (productIds.length > 0) {\n const { data, error } = await pub.from('products').select('id, name, price').in('id', productIds)\n supabaseError('Could not read recipe products', error)\n for (const product of data ?? []) productsById.set(product.id, product)\n }\n return rows.map((row) => mapRecipeRow({ ...row, products: productsById.get(row.product_id) }))\n}\n\n/** Hydrate ingredient costing without a nested PostgREST relationship select. */\nasync function hydrateRecipeIngredientRows(\n pub: any,\n rows: Record<string, any>[],\n includeGroups: boolean,\n): Promise<RecipeIngredient[]> {\n const productIds = [...new Set(rows.map((row) => row.product_id).filter(Boolean))]\n const productsById = new Map<string, Record<string, any>>()\n const detailsByProductId = new Map<string, Record<string, any>>()\n const unitsById = new Map<string, Record<string, any>>()\n\n if (productIds.length > 0) {\n const [{ data: products, error: productsError }, { data: details, error: detailsError }] = await Promise.all([\n pub.from('products').select('id, name, cost').in('id', productIds),\n pub.from(T.productDetails).select('product_id, conversion_factor, measurement_unit_id, purchase_unit_id').in('product_id', productIds),\n ])\n supabaseError('Could not read recipe ingredient products', productsError)\n supabaseError('Could not read recipe ingredient details', detailsError)\n for (const product of products ?? []) productsById.set(product.id, product)\n for (const detail of details ?? []) detailsByProductId.set(detail.product_id, detail)\n\n const unitIds = [...new Set([\n ...rows.map((row) => row.unit_id),\n ...(details ?? []).map((detail: Record<string, any>) => detail.measurement_unit_id),\n ].filter(Boolean))]\n if (unitIds.length > 0) {\n const { data: units, error: unitsError } = await pub\n .from(T.measurementUnits)\n .select('id, name, abbreviation')\n .in('id', unitIds)\n supabaseError('Could not read recipe ingredient units', unitsError)\n for (const unit of units ?? []) unitsById.set(unit.id, unit)\n }\n }\n\n const groupsById = new Map<string, Record<string, any>>()\n if (includeGroups) {\n const groupIds = [...new Set(rows.map((row) => row.group_id).filter(Boolean))]\n if (groupIds.length > 0) {\n const { data, error } = await pub.from(T.recipeGroups).select('id, name').in('id', groupIds)\n supabaseError('Could not read recipe groups', error)\n for (const group of data ?? []) groupsById.set(group.id, group)\n }\n }\n\n return rows.map((row) => {\n const product = productsById.get(row.product_id)\n const details = detailsByProductId.get(row.product_id)\n const hydratedProduct = product\n ? { ...product, [T.productDetails]: details }\n : undefined\n const ingredient = mapRecipeIngredientRow({\n ...row,\n products: hydratedProduct,\n [T.recipeGroups]: groupsById.get(row.group_id),\n })\n const unitId = row.unit_id ?? details?.measurement_unit_id\n const unit = unitId ? unitsById.get(unitId) : undefined\n ingredient.unitId = unitId ?? ingredient.unitId\n ingredient.unitName = unit?.abbreviation ?? unit?.name ?? ingredient.unitName\n return ingredient\n })\n}\n\n/** PostgREST returns a one-to-one embed as an object or a single-element array. */\nfunction embedded(value: unknown): Record<string, any> | undefined {\n const one = Array.isArray(value) ? value[0] : value\n return one && typeof one === 'object' ? (one as Record<string, any>) : undefined\n}\n\n/** The row without its embeds — snakeToCamel would otherwise carry them through\n * under mangled keys (`plgInventoryRecipeGroups`). */\nfunction withoutEmbeds(row: Record<string, any>, keys: string[]): Record<string, any> {\n const copy = { ...row }\n for (const key of keys) delete copy[key]\n return copy\n}\n\nfunction mapRecipeRow(row: Record<string, any>): Recipe {\n const recipe = snakeToCamel(withoutEmbeds(row, ['products'])) as any\n const product = embedded(row.products)\n if (product) {\n recipe.productName = product.name ?? recipe.productName\n recipe.productSalePrice = product.price ?? undefined\n }\n return recipe as Recipe\n}\n\nfunction mapRecipeIngredientRow(row: Record<string, any>): RecipeIngredient {\n const ing = snakeToCamel(withoutEmbeds(row, ['products', T.recipeGroups])) as any\n const group = embedded(row[T.recipeGroups])\n if (group) ing.groupName = group.name\n const product = embedded(row.products)\n if (product) {\n const details = embedded(product[T.productDetails])\n ing.productName = product.name ?? ing.productName\n ing.costBasis = {\n cost: Number(product.cost) || 0,\n conversionFactor: details?.conversion_factor ?? undefined,\n purchaseUnitId: details?.purchase_unit_id ?? undefined,\n }\n }\n return ing as RecipeIngredient\n}\n\n/** A session carries where and what it counts, resolved for the list. */\nconst COUNT_SESSION_SELECT =\n `*, ${T.stockLocations}(name), ${T.productCategories}(name)`\n\nfunction mapCountSessionRow(row: Record<string, any>): StockCountSession {\n const session = snakeToCamel(\n withoutEmbeds(row, [T.stockLocations, T.productCategories]),\n ) as any\n session.stockLocationName = embedded(row[T.stockLocations])?.name\n session.categoryName = embedded(row[T.productCategories])?.name\n session.blind = row.blind ?? true\n return session as StockCountSession\n}\n\nfunction mapCountItemRow(row: Record<string, any>): StockCountItem {\n const item = snakeToCamel(withoutEmbeds(row, ['products'])) as any\n const product = embedded(row.products)\n if (product) {\n item.productName = product.name\n item.productSku = product.sku ?? undefined\n }\n item.systemQuantity = Number(row.system_quantity) || 0\n // NULL stays undefined: nobody counted this line, which is not zero.\n item.countedQuantity = row.counted_quantity == null ? undefined : Number(row.counted_quantity)\n item.unitCost = Number(row.unit_cost) || 0\n return item as StockCountItem\n}\n\n/**\n * Map a public.products row to our Product type.\n *\n * Products are the spine archetype, so anything inventory-specific lives either\n * in `metadata` (free-form attributes) or in plg_inventory_product_details (the\n * things that are foreign keys and need referential integrity).\n */\nfunction mapProductRow(row: Record<string, any>): Product {\n const meta = row.metadata ?? {}\n // PostgREST returns an embedded one-to-one as an object or a single-element\n // array depending on how it inferred the relationship.\n const rawDetails = row[T.productDetails]\n const d = (Array.isArray(rawDetails) ? rawDetails[0] : rawDetails) ?? {}\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n sku: row.sku,\n barcode: meta.barcode,\n brand: meta.brand,\n productType: meta.productType ?? 'sale',\n currentQuantity: row.stock ?? 0,\n minQuantity: row.min_stock ?? 0,\n maxQuantity: meta.maxQuantity,\n costPrice: row.cost ?? 0,\n salePrice: row.price,\n categoryId: d.category_id ?? undefined,\n measurementUnitId: d.measurement_unit_id ?? undefined,\n purchaseUnitId: d.purchase_unit_id ?? undefined,\n conversionFactor: d.conversion_factor ?? undefined,\n supplierId: d.supplier_id ?? undefined,\n defaultLocationId: d.default_location_id ?? undefined,\n purpose: d.purpose ?? undefined,\n isActive: row.is_active ?? true,\n imageUrl: row.image_url,\n metadata: meta,\n tenantId: row.tenant_id,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\n/** The satellite columns, or null when the caller touched none of them. */\nfunction productDetailsRow(\n input: Partial<CreateProductInput>,\n): Record<string, unknown> | null {\n const row: Record<string, unknown> = {}\n if (input.categoryId !== undefined) row.category_id = input.categoryId || null\n if (input.measurementUnitId !== undefined) row.measurement_unit_id = input.measurementUnitId || null\n if (input.purchaseUnitId !== undefined) row.purchase_unit_id = input.purchaseUnitId || null\n if (input.conversionFactor !== undefined) row.conversion_factor = input.conversionFactor ?? 1\n if (input.supplierId !== undefined) row.supplier_id = input.supplierId || null\n if (input.defaultLocationId !== undefined) row.default_location_id = input.defaultLocationId || null\n if (input.purpose !== undefined) row.purpose = input.purpose || null\n return Object.keys(row).length > 0 ? row : null\n}\n\nfunction consumptionKey(sourceType: string, sourceId: string): string {\n return `${sourceType.trim()}:${sourceId.trim()}`\n}\n\nfunction assertConsumptionSource(sourceType: string, sourceId: string): void {\n if (!sourceType.trim()) throw new Error('Inventory consumption requires a source type')\n if (!sourceId.trim()) throw new Error('Inventory consumption requires a source id')\n}\n\n/**\n * Move one (product, location, batch, expiry) slot, and report how much the\n * on-hand total actually changed.\n *\n * `mode: 'add'` shifts the slot by `amount`; `mode: 'set'` makes the slot BE\n * `amount`. The distinction is the movement vocabulary's: an `adjustment`\n * declares `effect: 'set'` — it is the counted truth, not a delta — while entry\n * and exit are deltas. Returning the effective delta is what lets the caller\n * keep `products.stock` in step without re-reading the slot.\n *\n * The slot is identified by the full key of uq_..._slot (006), not just\n * product+location — before that index existed a product could hold several\n * rows per location and this read picked an arbitrary one. On the insert race\n * we retry once against the row the other writer just created; the unique index\n * is what makes that retry correct instead of producing a second row.\n */\nasync function applyPositionDelta(\n pub: any,\n tenantId: string | undefined,\n input: CreateStockMovementInput,\n locationId: string,\n amount: number,\n mode: 'add' | 'set' = 'add',\n): Promise<number> {\n const slot = (qb: any) => qb\n .eq('product_id', input.productId)\n .eq('stock_location_id', locationId)\n .is('batch_number', input.batchNumber ?? null)\n .is('expiration_date', input.expirationDate ?? null)\n\n const bump = async (): Promise<number | null> => {\n const { data: existing, error } = await slot(\n pub.from(T.stockPositions).select('id, quantity'),\n ).maybeSingle()\n if (error) throw new Error(error.message)\n if (!existing) return null\n const current = Number(existing.quantity) || 0\n const next = mode === 'set' ? amount : current + amount\n const { error: updateError } = await pub.from(T.stockPositions)\n .update({ quantity: next, unit_cost: input.unitCost ?? 0 })\n .eq('id', existing.id)\n if (updateError) throw new Error(updateError.message)\n return next - current\n }\n\n const bumped = await bump()\n if (bumped !== null) return bumped\n\n const { error: insertError } = await pub.from(T.stockPositions).insert({\n tenant_id: tenantId,\n product_id: input.productId,\n stock_location_id: locationId,\n quantity: amount,\n unit_cost: input.unitCost ?? 0,\n batch_number: input.batchNumber ?? null,\n expiration_date: input.expirationDate ?? null,\n })\n if (!insertError) return amount\n\n // 23505 = another writer created the slot between our read and our insert.\n if ((insertError as any).code === '23505') {\n const retried = await bump()\n if (retried !== null) return retried\n }\n throw new Error(insertError.message)\n}\n\n/**\n * The unit a tenant-wide default belongs to, when no unit is active.\n *\n * Reads `public.locations` rather than `app.units`: it is the write-through\n * projection of the same rows, shares their id, and is the one PostgREST can\n * reach. HQ first, because that is the unit `create_tenant` always makes.\n */\nasync function defaultUnitId(pub: any, tenantId: string): Promise<string | undefined> {\n const { data } = await pub\n .from('v_units')\n .select('id, kind')\n .eq('tenant_id', tenantId)\n .order('kind', { ascending: true })\n .limit(50)\n const rows = (data ?? []) as Array<{ id: string; kind?: string | null }>\n return (rows.find((r) => r.kind === 'hq') ?? rows[0])?.id\n}\n\nexport function createSupabaseInventoryProvider(): InventoryDataProvider {\n // Lazy resolution — Supabase client may not exist at factory time\n // but will be available when methods are called (after createSaasApp initializes it)\n function getClients() {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return { core: supabase, pub: supabase }\n }\n\n const provider: InventoryDataProvider = {\n async ensureReferenceData(): Promise<void> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) return\n\n const running = referenceDataPromises.get(tenantId)\n if (running) return running\n\n const prepare = (async () => {\n // Onboarding used to claim these rows were ready while only writing a\n // localStorage flag. Fill only what is missing so existing tenant\n // customisations remain untouched and repeated mounts are harmless.\n const { data: units, error: unitsError } = await pub\n .from(T.measurementUnits)\n .select('id, abbreviation, created_at')\n .eq('tenant_id', tenantId)\n if (unitsError) throw new Error(unitsError.message)\n\n // React StrictMode exposed the old check-then-insert race by mounting\n // the form twice. Collapse only duplicate DEFAULT abbreviations and\n // keep the oldest row; custom units are never candidates for removal.\n const duplicateIds = getDuplicateDefaultUnitIds(units ?? [])\n if (duplicateIds.length > 0) {\n const { error } = await pub.from(T.measurementUnits).delete().in('id', duplicateIds)\n if (error) throw new Error(error.message)\n }\n\n const missing = getMissingMeasurementUnits(units ?? [])\n if (missing.length > 0) {\n const { error } = await pub.from(T.measurementUnits).insert(\n missing.map((unit) => ({ ...unit, tenant_id: tenantId, is_active: true })),\n )\n if (error) throw new Error(error.message)\n }\n\n // Keep the second onboarding promise true as well: stock movements and\n // the product form need at least one place to point at.\n const { data: locations, error: locationError } = await pub\n .from(T.stockLocations)\n .select('id, name, created_at')\n .eq('tenant_id', tenantId)\n if (locationError) throw new Error(locationError.message)\n\n const duplicateLocationIds = getDuplicateAutoCreatedLocationIds(locations ?? [])\n if (duplicateLocationIds.length > 0) {\n const { error } = await pub.from(T.stockLocations).delete().in('id', duplicateLocationIds)\n if (error) throw new Error(error.message)\n }\n\n if (!locations || locations.length === 0) {\n // `unit_id` is NOT NULL since migration 136 made stock location a\n // unit-scoped table — a place to keep stock is somewhere, by\n // definition. This insert did not send one, so onboarding 400'd on\n // every tenant created after 136; the tenants that do have a default\n // location got it before the constraint. 136's own comment predicted\n // this exact failure: \"the constraint is about the writers\".\n const unitId = getActiveUnitId() ?? (await defaultUnitId(pub, tenantId))\n if (!unitId) {\n throw new Error(\n 'inventory: the tenant has no unit to attach the default stock location to',\n )\n }\n const { error } = await pub.from(T.stockLocations).insert({\n tenant_id: tenantId,\n unit_id: unitId,\n ...DEFAULT_STOCK_LOCATION,\n is_active: true,\n })\n if (error) throw new Error(error.message)\n }\n })()\n\n referenceDataPromises.set(tenantId, prepare)\n try {\n await prepare\n } finally {\n if (referenceDataPromises.get(tenantId) === prepare) referenceDataPromises.delete(tenantId)\n }\n },\n\n // --- Products (public.products) ---\n async getProducts(query: ProductQuery): Promise<PaginatedResult<Product>> {\n const { core, pub } = getClients()\n // `!inner` only when filtering on a satellite column, so products without\n // a details row are not dropped from an unfiltered list.\n const select = query.categoryId ? `*, ${T.productDetails}!inner(*)` : PRODUCT_SELECT\n // v_inventory_products, not products: spine 188 dropped products.stock\n // and products.min_stock, and 027 publishes them derived under the same\n // names. Reads come from the view; writes still go to the table.\n let qb = core.from(PRODUCTS_READ).select(select, { count: 'exact' })\n if (query.search) qb = qb.ilike('name', `%${query.search}%`)\n // productType lives in the metadata JSON column → filter on metadata->>productType.\n if (query.productType) qb = qb.eq('metadata->>productType', query.productType)\n if (query.categoryId) qb = qb.eq(`${T.productDetails}.category_id`, query.categoryId)\n if (query.isActive !== undefined) qb = qb.eq('is_active', query.isActive)\n if (query.lowStockOnly) qb = qb.lte('stock', 0) // simplified\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 50\n qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order('created_at', { ascending: false })\n const { data, count } = await qb\n return { data: (data ?? []).map(mapProductRow), total: count ?? 0 }\n },\n\n async getProductById(id: string): Promise<Product | null> {\n const { core } = getClients()\n const { data } = await core.from(PRODUCTS_READ).select(PRODUCT_SELECT).eq('id', id).single()\n return data ? mapProductRow(data) : null\n },\n\n async createProduct(input: CreateProductInput): Promise<Product> {\n const { core } = getClients()\n const tenantId = getTenantId()\n const row: Record<string, unknown> = {\n tenant_id: tenantId,\n name: input.name,\n description: input.description,\n sku: input.sku,\n price: input.salePrice ?? 0,\n cost: input.costPrice ?? 0,\n is_active: true,\n image_url: input.imageUrl,\n metadata: { productType: input.productType, barcode: input.barcode, brand: input.brand, maxQuantity: input.maxQuantity },\n }\n const { data, error } = await core.from('products').insert(row).select().single()\n if (error) throw new Error(error.message)\n\n // The minimum is the plugin's, and lives in its own table since 027 —\n // products.min_stock was a mirror of exactly this row.\n if (input.minQuantity !== undefined || input.maxQuantity !== undefined) {\n await core.from('plg_inventory_product_settings').upsert(\n { tenant_id: tenantId, product_id: data!.id, min_quantity: input.minQuantity ?? 0, max_quantity: input.maxQuantity ?? null },\n { onConflict: 'tenant_id,product_id,unit_id' },\n )\n }\n\n const details = productDetailsRow(input)\n if (details) {\n const { error: detailsError } = await core.from(T.productDetails)\n .upsert({ ...details, product_id: data!.id, tenant_id: tenantId }, { onConflict: 'product_id' })\n if (detailsError) throw new Error(detailsError.message)\n }\n return (await provider.getProductById(data!.id)) ?? mapProductRow(data!)\n },\n\n async updateProduct(id: string, partial: Partial<Product>): Promise<Product> {\n const { core } = getClients()\n const tenantId = getTenantId()\n const row: Record<string, unknown> = {}\n if (partial.name !== undefined) row.name = partial.name\n if (partial.description !== undefined) row.description = partial.description\n if (partial.sku !== undefined) row.sku = partial.sku\n if (partial.salePrice !== undefined) row.price = partial.salePrice\n if (partial.costPrice !== undefined) row.cost = partial.costPrice\n if (partial.isActive !== undefined) row.is_active = partial.isActive\n if (partial.imageUrl !== undefined) row.image_url = partial.imageUrl\n\n const metaPatch: Record<string, unknown> = {}\n if (partial.productType !== undefined) metaPatch.productType = partial.productType\n if (partial.barcode !== undefined) metaPatch.barcode = partial.barcode\n if (partial.brand !== undefined) metaPatch.brand = partial.brand\n if (partial.maxQuantity !== undefined) metaPatch.maxQuantity = partial.maxQuantity\n if (Object.keys(metaPatch).length > 0) {\n // Merge, never replace: this used to assign a fresh object, which wiped\n // every key the caller did not happen to mention (maxQuantity most of\n // all) and wrote undefined for the ones it mentioned but left unset.\n const { data: current } = await core.from('products').select('metadata').eq('id', id).single()\n row.metadata = { ...(current?.metadata ?? {}), ...metaPatch }\n }\n\n if (Object.keys(row).length > 0) {\n const { error } = await core.from('products').update(row).eq('id', id)\n if (error) throw new Error(error.message)\n }\n\n if (partial.minQuantity !== undefined) {\n await core.from('plg_inventory_product_settings').upsert(\n { tenant_id: tenantId, product_id: id, min_quantity: partial.minQuantity },\n { onConflict: 'tenant_id,product_id,unit_id' },\n )\n }\n\n const details = productDetailsRow(partial)\n if (details) {\n const { error: detailsError } = await core.from(T.productDetails)\n .upsert({ ...details, product_id: id, tenant_id: tenantId }, { onConflict: 'product_id' })\n if (detailsError) throw new Error(detailsError.message)\n }\n\n const updated = await provider.getProductById(id)\n if (!updated) throw new Error(`Product ${id} not found after update`)\n return updated\n },\n\n async uploadProductImage(productId: string, file: File): Promise<string> {\n const { core } = getClients()\n const tenantId = getTenantId()\n if (!tenantId) throw new Error('Nenhum estabelecimento ativo para enviar a foto.')\n if (!file.type.startsWith('image/')) throw new Error('Selecione um arquivo de imagem.')\n if (file.size > 8 * 1024 * 1024) throw new Error('A foto deve ter no máximo 8 MB.')\n\n const extension = file.name.split('.').pop()?.toLowerCase().replace(/[^a-z0-9]/g, '') || 'jpg'\n const objectId = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : `${Date.now()}-${Math.random().toString(36).slice(2)}`\n const path = `${tenantId}/products/${productId}/${objectId}.${extension}`\n const bucket = core.storage.from('inventory-images')\n const { error: uploadError } = await bucket.upload(path, file, {\n cacheControl: '31536000',\n contentType: file.type,\n upsert: false,\n })\n if (uploadError) throw new Error(uploadError.message)\n\n const { data: { publicUrl } } = bucket.getPublicUrl(path)\n const { error: registerError } = await core.rpc('inventory_register_product_image', {\n p_product: productId,\n p_storage_path: path,\n p_public_url: publicUrl,\n p_file_name: file.name,\n p_file_size: file.size,\n p_mime_type: file.type,\n })\n if (registerError) {\n // A file without a canonical document row becomes permanent garbage.\n // Best-effort cleanup keeps a failed register call recoverable.\n await bucket.remove([path])\n throw new Error(registerError.message)\n }\n return publicUrl\n },\n\n // --- Stock Movements (via view with product join — single query) ---\n async getMovements(query: MovementQuery): Promise<PaginatedResult<StockMovement>> {\n const { pub } = getClients()\n // Single query via v_stock_movements view (JOINs with public.products)\n let qb = pub.from('v_stock_movements').select('*', { count: 'exact' })\n if (query.productId) qb = qb.eq('product_id', query.productId)\n if (query.movementType) {\n const types = Array.isArray(query.movementType) ? query.movementType : [query.movementType]\n qb = qb.in('movement_type', types)\n }\n if (query.stockLocationId) qb = qb.eq('stock_location_id', query.stockLocationId)\n if (query.dateRange) qb = qb.gte('movement_date', query.dateRange.from).lte('movement_date', query.dateRange.to)\n if (query.search) qb = qb.ilike('product_name', `%${query.search}%`)\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 50\n qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order('movement_date', { ascending: false })\n const { data, count } = await qb\n\n const movements = (data ?? []).map((r: any) => {\n const mov = snakeToCamel(r) as any\n mov.productName = r.product_name ?? mov.productName\n mov.productSku = r.product_sku ?? mov.productSku\n // View may include location names if the updated migration has been applied\n mov.stockLocationName = r.stock_location_name ?? mov.stockLocationName\n mov.destinationLocationName = r.destination_location_name ?? mov.destinationLocationName\n return mov as StockMovement\n })\n\n // Resolve location names if not provided by the view\n const needsLocationResolve = movements.some(\n (m: any) => (m.stockLocationId && !m.stockLocationName) || (m.destinationLocationId && !m.destinationLocationName)\n )\n if (needsLocationResolve) {\n const locationIds = new Set<string>()\n for (const m of movements) {\n if (m.stockLocationId && !m.stockLocationName) locationIds.add(m.stockLocationId)\n if (m.destinationLocationId && !m.destinationLocationName) locationIds.add(m.destinationLocationId)\n }\n if (locationIds.size > 0) {\n const { data: locs } = await pub.from(T.stockLocations).select('id, name').in('id', [...locationIds])\n const locMap = new Map((locs ?? []).map((l: any) => [l.id, l.name]))\n for (const m of movements) {\n if (m.stockLocationId && !m.stockLocationName) m.stockLocationName = locMap.get(m.stockLocationId)\n if (m.destinationLocationId && !m.destinationLocationName) m.destinationLocationName = locMap.get(m.destinationLocationId)\n }\n }\n }\n\n return { data: movements, total: count ?? 0 }\n },\n\n async createMovement(input: CreateStockMovementInput): Promise<StockMovement> {\n const { core, pub } = getClients()\n const tenantId = getTenantId()\n const unitCost = input.unitCost ?? 0\n // `movement_type` and `stock_location_id` are GENERATED ALWAYS mirrors of\n // `kind` and `source_location_id` — the deprecated pair from issue #352 —\n // so camelToSnake handing them straight through was an outright refusal\n // (\"cannot insert a non-DEFAULT value into column movement_type\"), not a\n // duplicate. The vocabulary differs too: the UI says entry/exit, the\n // ledger's CHECK says in/out, and its sign check requires an `out` to be\n // negative.\n const kind = LEDGER_KIND[input.movementType] ?? 'adjust'\n const signed = kind === 'out' || kind === 'transfer'\n ? -Math.abs(input.quantity)\n : kind === 'in' ? Math.abs(input.quantity) : input.quantity\n\n // THROUGH THE RPCs, not an INSERT.\n //\n // `plg_inventory_stock_movements` denies direct client writes — the\n // internal_only trigger and the absent grant are what make the ledger\n // append-only in practice (\"permission denied for table\n // plg_inventory_stock_movements\"). `inventory_receive` and\n // `inventory_adjust` are the doors: SECURITY DEFINER, permission-checked,\n // idempotent by key, and they file the operation AND recompute the\n // position — which is why the manual position update below is gone with\n // them. Doing both would count the same movement twice.\n const line: Record<string, unknown> = {\n product_id: input.productId,\n quantity: signed,\n ...(input.unitCost != null ? { unit_cost: input.unitCost } : {}),\n ...(input.batchNumber ? { batch_number: input.batchNumber } : {}),\n ...(input.expirationDate ? { expiration_date: input.expirationDate } : {}),\n ...(input.notes ? { notes: input.notes } : {}),\n }\n // The RPC takes the location as a REQUIRED argument, and PostgREST matches\n // an overload by the argument names it receives — so an undefined\n // `p_location` is not \"use the default\", it is a different function that\n // does not exist (\"Could not find the function\n // public.inventory_receive(p_document, p_lines)\"). A screen that did not\n // ask which shelf still has to name one.\n const locationId = input.stockLocationId ?? await defaultLocationId(pub, tenantId)\n if (!locationId) {\n throw new Error('inventory: this tenant has no stock location to record the movement against')\n }\n\n const { data: opResult, error } = kind === 'in'\n ? await pub.rpc('inventory_receive', {\n p_location: locationId,\n p_lines: [line],\n p_document: {\n type: 'manual',\n ...(input.documentNumber ? { ref: input.documentNumber } : {}),\n ...(input.supplierId ? { supplier_id: input.supplierId } : {}),\n ...(input.movementDate ? { date: input.movementDate } : {}),\n },\n })\n : await pub.rpc('inventory_adjust', {\n p_location: locationId,\n p_lines: [line],\n // The ledger refuses an adjustment with no reason, and the verb is one\n // when the user did not type another.\n p_reason: input.reason ?? input.movementType,\n })\n if (error) throw new Error(error.message)\n\n const written = (opResult as { movements?: any[] } | null)?.movements?.[0]\n if (!written) throw new Error('inventory: the ledger accepted the operation but returned no movement')\n const data = { ...written, tenant_id: tenantId, movement_type: input.movementType }\n\n // Fetch product name for the response.\n const { data: product } = await core.from(PRODUCTS_READ).select('id, name, stock').eq('id', input.productId).single()\n\n // THE POSITION IS NOT UPDATED HERE ANY MORE.\n //\n // `inventory_receive` / `inventory_adjust` recompute it inside the same\n // transaction as the movement — that is most of why they exist. The block\n // that used to live here read the slot and wrote it back by hand, which\n // beside the RPC would count every movement twice: the ledger once and\n // this once. An adjustment's \"set\" semantics are the RPC's too, through\n // its own `set_quantity` line, so nothing about the vocabulary is lost.\n\n const movement = snakeToCamel(data) as any\n movement.productName = product?.name\n // Resolve location name\n if (input.stockLocationId) {\n const { data: loc } = await pub.from(T.stockLocations).select('name').eq('id', input.stockLocationId).single()\n movement.stockLocationName = loc?.name\n }\n if (input.destinationLocationId) {\n const { data: loc } = await pub.from(T.stockLocations).select('name').eq('id', input.destinationLocationId).single()\n movement.destinationLocationName = loc?.name\n }\n if (input.supplierId) {\n const { data: supplier } = await core.from('people').select('name').eq('id', input.supplierId).single()\n movement.supplierName = supplier?.name\n }\n return movement as StockMovement\n },\n\n /**\n * Undo a movement: the ledger row goes and the stock it moved comes back.\n * Position and on-hand are unwound with the same rules createMovement\n * applied, so a reversal cannot leave the two disagreeing.\n */\n async reverseMovement(movementId: string): Promise<void> {\n const { core, pub } = getClients()\n const tenantId = getTenantId()\n const { data: row, error } = await pub.from(T.stockMovements).select('*').eq('id', movementId).single()\n if (error) throw new Error(error.message)\n if (!row) throw new Error(`Movement ${movementId} not found`)\n\n const movementType = row.movement_type as MovementType\n const quantity = Number(row.quantity) || 0\n // Same slot key the movement wrote to; unit_cost follows the undone\n // movement because no earlier cost survives on the position.\n const slot: CreateStockMovementInput = {\n productId: row.product_id,\n quantity,\n movementType,\n unitCost: row.unit_cost ?? 0,\n batchNumber: row.batch_number ?? undefined,\n expirationDate: row.expiration_date ?? undefined,\n }\n\n // The ledger row goes FIRST, and `select()` is what makes a delete the RLS\n // refused fail loudly — PostgREST reports deleting nothing as success, and\n // unwinding the stock behind that would leave the two disagreeing.\n const { data: deleted, error: deleteError } = await pub.from(T.stockMovements)\n .delete().eq('id', movementId).select('id')\n if (deleteError) throw new Error(deleteError.message)\n if (!deleted || deleted.length === 0) throw new Error(`Movement ${movementId} could not be deleted`)\n\n // Undoing the ledger row is undoing the balance: the position delta below\n // is the whole of it since 188 dropped products.stock. There is no second\n // number to unwind, which is the point.\n\n if (row.stock_location_id) {\n await applyPositionDelta(pub, tenantId, slot, row.stock_location_id, movementType === 'entry' ? -quantity : quantity)\n if (movementType === 'transfer' && row.destination_location_id) {\n await applyPositionDelta(pub, tenantId, slot, row.destination_location_id, -quantity)\n }\n }\n },\n\n // --- Stock Positions ---\n async getPositions(productId: string): Promise<StockPosition[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.stockPositions).select('*').eq('product_id', productId)\n const positions: StockPosition[] = (data ?? []).map((r: any) => snakeToCamel(r) as unknown as StockPosition)\n\n const locationIds = [...new Set(positions.map((p) => p.stockLocationId).filter(Boolean) as string[])]\n if (locationIds.length > 0) {\n const { data: locs } = await pub.from(T.stockLocations).select('id, name').in('id', locationIds)\n const byId = new Map<string, string>((locs ?? []).map((l: any) => [l.id, l.name]))\n for (const p of positions) {\n if (p.stockLocationId) p.stockLocationName = byId.get(p.stockLocationId)\n }\n }\n return positions\n },\n\n // --- Stock Locations ---\n async getLocations(): Promise<StockLocation[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.stockLocations).select('*').eq('is_active', true).order('name')\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as StockLocation)\n },\n\n async createLocation(input): Promise<StockLocation> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { data } = await pub.from(T.stockLocations).insert({ ...camelToSnake(input as any), tenant_id: tenantId }).select().single()\n return snakeToCamel(data!) as unknown as StockLocation\n },\n\n // --- Suppliers (same rows the suppliers registry edits) ---\n async getSuppliers(): Promise<Supplier[]> {\n const { core } = getClients()\n const { data } = await core.from('people')\n .select('id, name, document_number, phone')\n .eq('kind', 'supplier').eq('is_active', true)\n .order('name').limit(200)\n return (data ?? []).map((r: any) => ({\n id: r.id, name: r.name,\n documentNumber: r.document_number ?? undefined,\n phone: r.phone ?? undefined,\n }))\n },\n\n // --- Categories ---\n async getCategories(): Promise<ProductCategory[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.productCategories).select('*').eq('is_active', true).order('name')\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as ProductCategory)\n },\n\n // --- Stock counts ---\n async getCountSessions(): Promise<StockCountSession[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countSessions)\n .select(COUNT_SESSION_SELECT).order('opened_at', { ascending: false }).limit(100)\n const sessions: StockCountSession[] = (data ?? []).map(mapCountSessionRow)\n if (sessions.length === 0) return sessions\n\n // The progress columns in one round trip instead of a query per row.\n const { data: lines } = await pub.from(T.countItems)\n .select('session_id, system_quantity, counted_quantity')\n .in('session_id', sessions.map((s) => s.id))\n const tally = new Map<string, { total: number; counted: number; divergent: number }>()\n for (const line of lines ?? []) {\n const bucket = tally.get(line.session_id) ?? { total: 0, counted: 0, divergent: 0 }\n bucket.total += 1\n if (line.counted_quantity != null) {\n bucket.counted += 1\n if (Number(line.counted_quantity) !== Number(line.system_quantity)) bucket.divergent += 1\n }\n tally.set(line.session_id, bucket)\n }\n for (const session of sessions) {\n const bucket = tally.get(session.id)\n session.itemCount = bucket?.total ?? 0\n session.countedCount = bucket?.counted ?? 0\n session.divergentCount = bucket?.divergent ?? 0\n }\n return sessions\n },\n\n async getCountSession(id: string): Promise<StockCountSession | null> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countSessions).select(COUNT_SESSION_SELECT).eq('id', id).maybeSingle()\n return data ? mapCountSessionRow(data) : null\n },\n\n async getCountItems(sessionId: string): Promise<StockCountItem[]> {\n const { pub } = getClients()\n const { data } = await pub.from(T.countItems)\n .select('*, products(name, sku)').eq('session_id', sessionId)\n const items: StockCountItem[] = (data ?? []).map(mapCountItemRow)\n return items.sort((a, b) => (a.productName ?? '').localeCompare(b.productName ?? ''))\n },\n\n async openCountSession(input: OpenStockCountInput): Promise<StockCountSession> {\n const { pub } = getClients()\n // The snapshot has to be one consistent read, so the RPC does both.\n const { data, error } = await pub.rpc('inventory_open_count_session', {\n p_stock_location_id: input.stockLocationId,\n p_category_id: input.categoryId ?? null,\n p_reference: input.reference ?? null,\n p_blind: input.blind ?? true,\n p_notes: input.notes ?? null,\n })\n if (error) throw new Error(error.message)\n const session = await provider.getCountSession(data as string)\n if (!session) throw new Error('Count session could not be read after opening')\n return session\n },\n\n async saveCountEntry(itemId: string, quantity: number | null, notes?: string): Promise<StockCountItem> {\n const { pub } = getClients()\n const row: Record<string, unknown> = {\n counted_quantity: quantity,\n counted_at: quantity == null ? null : new Date().toISOString(),\n updated_at: new Date().toISOString(),\n }\n if (notes !== undefined) row.notes = notes || null\n const { data, error } = await pub.from(T.countItems)\n .update(row).eq('id', itemId).select('*, products(name, sku)').single()\n if (error) throw new Error(error.message)\n\n // The first entry typed is what turns an open session into a count.\n await pub.from(T.countSessions)\n .update({ status: 'counting', updated_at: new Date().toISOString() })\n .eq('id', data.session_id).eq('status', 'open')\n return mapCountItemRow(data)\n },\n\n async closeCountSession(sessionId: string, reason?: string): Promise<CloseStockCountResult> {\n const { pub } = getClients()\n const { data, error } = await pub.rpc('inventory_close_count_session', {\n p_session_id: sessionId,\n p_reason: reason ?? null,\n })\n if (error) throw new Error(error.message)\n const result = (data ?? {}) as Record<string, any>\n if (result.ok === false) throw new Error(result.error ?? 'Could not close the count')\n return {\n sessionId,\n adjustmentsCreated: Number(result.adjustments_created) || 0,\n alreadyClosed: result.already_closed === true,\n }\n },\n\n async cancelCountSession(sessionId: string): Promise<StockCountSession> {\n const { pub } = getClients()\n // `.neq('status','closed')` is the fence: a closed count has already moved\n // stock and cancelling it would claim otherwise.\n const { error } = await pub.from(T.countSessions)\n .update({ status: 'cancelled', updated_at: new Date().toISOString() })\n .eq('id', sessionId).neq('status', 'closed')\n if (error) throw new Error(error.message)\n const session = await provider.getCountSession(sessionId)\n if (!session) throw new Error(`Count session ${sessionId} not found`)\n return session\n },\n\n // --- Recipes ---\n async getRecipes(): Promise<Recipe[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipes).select('*').eq('is_active', true).order('name')\n supabaseError('Could not read recipes', error)\n return hydrateRecipeRows(pub, data ?? [])\n },\n\n async getRecipeById(id: string): Promise<Recipe | null> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipes).select('*').eq('id', id).maybeSingle()\n supabaseError('Could not read recipe', error)\n if (!data) return null\n return (await hydrateRecipeRows(pub, [data]))[0] ?? null\n },\n\n async getRecipeIngredients(recipeId: string): Promise<RecipeIngredient[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeIngredients)\n .select('*')\n .eq('recipe_id', recipeId)\n .order('display_order')\n supabaseError('Could not read recipe ingredients', error)\n return hydrateRecipeIngredientRows(pub, data ?? [], true)\n },\n\n async getAllRecipeIngredients(): Promise<RecipeIngredient[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeIngredients)\n .select('*')\n .order('display_order')\n supabaseError('Could not read recipe ingredients', error)\n return hydrateRecipeIngredientRows(pub, data ?? [], false)\n },\n\n async getRecipeGroups(recipeId: string): Promise<RecipeGroup[]> {\n const { pub } = getClients()\n const { data, error } = await pub.from(T.recipeGroups).select('*').eq('recipe_id', recipeId).order('display_order')\n supabaseError('Could not read recipe groups', error)\n return (data ?? []).map((r: any) => snakeToCamel(r) as unknown as RecipeGroup)\n },\n\n async createRecipe(input: CreateRecipeInput): Promise<Recipe> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { ingredients, ...recipeData } = input\n const { data: recipe, error: recipeError } = await pub.from(T.recipes)\n .insert({ ...camelToSnake(recipeData as any), tenant_id: tenantId })\n .select().single()\n supabaseError('Could not create recipe', recipeError)\n if (!recipe) throw new Error('Could not create recipe: Supabase returned no row')\n\n if (ingredients.length > 0) {\n const { error: ingredientsError } = await pub.from(T.recipeIngredients).insert(\n ingredients.map((ing) => ({ ...camelToSnake(ing as any), recipe_id: recipe.id, tenant_id: tenantId }))\n )\n if (ingredientsError) {\n // Do not leave a recipe that says it was saved while carrying no\n // technical sheet. This best-effort compensation keeps the direct\n // browser flow coherent until it moves to an atomic RPC.\n await pub.from(T.recipes).delete().eq('id', recipe.id)\n supabaseError('Could not create recipe ingredients', ingredientsError)\n }\n }\n\n // One active ficha per product. The form only ever creates, so re-saving\n // left the previous recipe active too — and `consumeRecipeForSource` reads\n // a SINGLE active recipe per product, which means a stale duplicate could\n // be the one deciding a stock movement. Retired only after the ingredients\n // landed, so a failed save never disables the sheet that still works.\n if (recipeData.productId) {\n const { error: retireError } = await pub.from(T.recipes)\n .update({ is_active: false })\n .eq('product_id', recipeData.productId)\n .eq('is_active', true)\n .neq('id', recipe.id)\n // The new sheet is saved and is the newest by `updated_at`, so it already\n // wins the lookup; a failed retirement is worth a warning, not a rollback.\n if (retireError) console.warn('Could not retire previous recipes', retireError.message)\n }\n\n return snakeToCamel(recipe!) as unknown as Recipe\n },\n\n async updateRecipe(id: string, patch: Partial<Recipe>): Promise<Recipe> {\n const { pub } = getClients()\n const row: Record<string, unknown> = {}\n if (patch.name !== undefined) row.name = patch.name\n if (patch.description !== undefined) row.description = patch.description\n if (patch.productId !== undefined) row.product_id = patch.productId || null\n if (patch.yieldQuantity !== undefined) row.yield_quantity = patch.yieldQuantity\n if (patch.preparationTimeMinutes !== undefined) row.preparation_time_minutes = patch.preparationTimeMinutes\n if (patch.instructions !== undefined) row.instructions = patch.instructions\n if (patch.isActive !== undefined) row.is_active = patch.isActive\n if (patch.metadata !== undefined) row.metadata = patch.metadata\n if (Object.keys(row).length > 0) {\n row.updated_at = new Date().toISOString()\n const { error } = await pub.from(T.recipes).update(row).eq('id', id)\n if (error) throw new Error(error.message)\n }\n const updated = await provider.getRecipeById(id)\n if (!updated) throw new Error(`Recipe ${id} not found after update`)\n return updated\n },\n\n async addRecipeIngredient(recipeId: string, input: CreateRecipeIngredientInput): Promise<RecipeIngredient> {\n const { pub } = getClients()\n const tenantId = getTenantId()\n const { data, error } = await pub.from(T.recipeIngredients)\n .insert({ ...camelToSnake(input as any), recipe_id: recipeId, tenant_id: tenantId })\n .select('*').single()\n supabaseError('Could not add recipe ingredient', error)\n if (!data) throw new Error('Could not add recipe ingredient: Supabase returned no row')\n return (await hydrateRecipeIngredientRows(pub, [data], true))[0]\n },\n\n async consumeRecipeForSource(input: ConsumeRecipeForSourceInput): Promise<InventoryConsumptionResult> {\n assertConsumptionSource(input.sourceType, input.sourceId)\n if (!input.productId) throw new Error('Inventory consumption requires a product id')\n if (!Number.isFinite(input.quantity) || input.quantity <= 0) {\n throw new Error('Inventory consumption quantity must be positive')\n }\n\n const { pub } = getClients()\n const idempotencyKey = consumptionKey(input.sourceType, input.sourceId)\n const { data: recipeRow, error: recipeError } = await pub.from(T.recipes)\n .select('*')\n .eq('product_id', input.productId)\n .eq('is_active', true)\n .order('updated_at', { ascending: false })\n .limit(1)\n .maybeSingle()\n if (recipeError) throw new Error(recipeError.message)\n if (!recipeRow) {\n return {\n sourceType: input.sourceType,\n sourceId: input.sourceId,\n idempotencyKey,\n status: 'skipped',\n lineCount: 0,\n skipReason: 'no_active_recipe',\n }\n }\n\n const recipe = mapRecipeRow(recipeRow)\n if (!Number.isFinite(recipe.yieldQuantity) || recipe.yieldQuantity <= 0) {\n throw new Error(`Recipe ${recipe.id} has an invalid yield quantity`)\n }\n\n const { data: ingredientRows, error: ingredientError } = await pub.from(T.recipeIngredients)\n .select('*')\n .eq('recipe_id', recipe.id)\n .order('display_order')\n if (ingredientError) throw new Error(ingredientError.message)\n if (!ingredientRows?.length) throw new Error(`Recipe ${recipe.id} has no ingredients`)\n\n const productIds = [...new Set(ingredientRows.map((row: any) => String(row.product_id)))]\n const [{ data: settingsRows, error: settingsError }, { data: detailRows, error: detailsError }] = await Promise.all([\n pub.from(T.productSettings)\n .select('product_id, unit_id, measurement_unit_id, default_location_id')\n .in('product_id', productIds)\n .is('unit_id', null),\n pub.from(T.productDetails)\n .select('product_id, measurement_unit_id, default_location_id')\n .in('product_id', productIds),\n ])\n if (settingsError) throw new Error(settingsError.message)\n if (detailsError) throw new Error(detailsError.message)\n\n const settingsByProduct = new Map(\n (settingsRows ?? []).map((row: any) => [String(row.product_id), row]),\n )\n const detailsByProduct = new Map(\n (detailRows ?? []).map((row: any) => [String(row.product_id), row]),\n )\n const factor = input.quantity / recipe.yieldQuantity\n const aggregate = new Map<string, Record<string, unknown>>()\n\n for (const row of ingredientRows as any[]) {\n const productId = String(row.product_id)\n const settings = settingsByProduct.get(productId) as any\n const details = detailsByProduct.get(productId) as any\n const locationId = settings?.default_location_id ?? details?.default_location_id\n if (!locationId) {\n throw new Error(`Ingredient ${productId} has no default stock location`)\n }\n const measurementUnitId = row.unit_id\n ?? settings?.measurement_unit_id\n ?? details?.measurement_unit_id\n ?? undefined\n const quantity = Math.round(Number(row.quantity) * factor * 10_000) / 10_000\n if (!Number.isFinite(quantity) || quantity <= 0) {\n throw new Error(`Recipe ${recipe.id} produced an invalid quantity for ingredient ${productId}`)\n }\n\n const lineKey = `${productId}:${locationId}:${measurementUnitId ?? ''}`\n const current = aggregate.get(lineKey)\n if (current) {\n current.quantity = Math.round((Number(current.quantity) + quantity) * 10_000) / 10_000\n } else {\n aggregate.set(lineKey, {\n product_id: productId,\n location_id: locationId,\n quantity,\n ...(measurementUnitId ? { measurement_unit_id: measurementUnitId } : {}),\n notes: `Recipe ${recipe.id}`,\n })\n }\n }\n\n const lines = [...aggregate.values()]\n const { error: reserveError } = await pub.rpc('inventory_reserve', {\n p_source_type: input.sourceType,\n p_source_id: input.sourceId,\n p_lines: lines,\n p_idempotency_key: idempotencyKey,\n })\n if (reserveError) throw new Error(reserveError.message)\n\n const { error: confirmError } = await pub.rpc('inventory_confirm', {\n p_idempotency_key: idempotencyKey,\n })\n if (confirmError) throw new Error(confirmError.message)\n\n return {\n sourceType: input.sourceType,\n sourceId: input.sourceId,\n idempotencyKey,\n status: 'confirmed',\n recipeId: recipe.id,\n lineCount: lines.length,\n }\n },\n\n async reverseRecipeConsumption(input: ReverseRecipeConsumptionInput): Promise<InventoryConsumptionResult> {\n assertConsumptionSource(input.sourceType, input.sourceId)\n if (!input.reason.trim()) throw new Error('Inventory consumption reversal requires a reason')\n\n const { pub } = getClients()\n const idempotencyKey = consumptionKey(input.sourceType, input.sourceId)\n const { count, error: lookupError } = await pub.from(T.reservations)\n .select('id', { count: 'exact', head: true })\n .eq('source_type', input.sourceType)\n .eq('source_id', input.sourceId)\n if (lookupError) throw new Error(lookupError.message)\n if (!count) {\n return {\n sourceType: input.sourceType,\n sourceId: input.sourceId,\n idempotencyKey,\n status: 'skipped',\n lineCount: 0,\n skipReason: 'nothing_to_reverse',\n }\n }\n\n const { data, error } = await pub.rpc('inventory_reverse', {\n p_idempotency_key: idempotencyKey,\n p_reason: input.reason,\n })\n if (error) throw new Error(error.message)\n return {\n sourceType: input.sourceType,\n sourceId: input.sourceId,\n idempotencyKey,\n status: 'reversed',\n lineCount: Number((data as any)?.reversed_lines) || count,\n }\n },\n\n // --- Usage audit ---\n async getUsageAudit(query: UsageAuditQuery): Promise<PaginatedResult<UsageAuditEntry>> {\n const { pub } = getClients()\n let qb = pub.from(USAGE_AUDIT_READ).select('*', { count: 'exact' })\n // A divergence is only a divergence against a standard: a line no recipe\n // answers for has nothing to be off by, so it is not a silent pass.\n if (query.divergentOnly) qb = qb.not('variance', 'is', null).neq('variance', 0)\n if (query.search) {\n // Commas and parentheses are the `or=` grammar itself, so a name typed\n // as \"Lima, Patrícia\" would come back a 400 instead of a result.\n const like = `%${query.search.replace(/[(),]/g, ' ').trim()}%`\n qb = qb.or(\n `product_name.ilike.${like},performed_by_name.ilike.${like},customer_name.ilike.${like},item_name.ilike.${like}`,\n )\n }\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 50\n qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order('used_at', { ascending: false })\n const { data, count, error } = await qb\n if (error) throw new Error(error.message)\n\n const entries = (data ?? []).map((r: any) => ({\n itemId: r.item_id,\n productId: r.product_id,\n productName: r.product_name ?? undefined,\n productSku: r.product_sku ?? undefined,\n usedAt: r.used_at,\n movementDate: r.movement_date,\n postedQuantity: Number(r.posted_quantity ?? 0),\n netQuantity: Number(r.net_quantity ?? 0),\n // Null is \"no standard to compare to\" and must survive the cast: 0 is a\n // standard of zero, which is a different statement.\n standardQuantity: r.standard_quantity == null ? null : Number(r.standard_quantity),\n variance: r.variance == null ? null : Number(r.variance),\n unitAbbreviation: r.unit_abbreviation ?? undefined,\n totalCost: Number(r.total_cost ?? 0),\n stockLocationId: r.stock_location_id ?? undefined,\n stockLocationName: r.stock_location_name ?? undefined,\n locationCount: Number(r.location_count ?? 1),\n recipeId: r.recipe_id ?? undefined,\n recipeName: r.recipe_name ?? undefined,\n orderId: r.order_id ?? undefined,\n itemName: r.item_name ?? undefined,\n orderReference: r.order_reference ?? undefined,\n performedById: r.performed_by_id ?? undefined,\n performedByName: r.performed_by_name ?? undefined,\n customerId: r.customer_id ?? undefined,\n customerName: r.customer_name ?? undefined,\n correctedAt: r.corrected_at ?? undefined,\n correctionReason: r.correction_reason ?? undefined,\n isCorrected: Boolean(r.is_corrected),\n })) as UsageAuditEntry[]\n\n return { data: entries, total: count ?? 0 }\n },\n\n async correctUsage(input: { itemId: string; productId: string; quantity: number; reason: string }): Promise<void> {\n const { pub } = getClients()\n const { error } = await pub.rpc('inventory_correct_usage', {\n p_item_id: input.itemId,\n p_product_id: input.productId,\n p_quantity: input.quantity,\n p_reason: input.reason,\n })\n if (error) throw new Error(error.message)\n },\n\n async correctUsageBatch(input: { reason: string; lines: UsageAuditCorrection[] }): Promise<UsageAuditBatchResult> {\n const { pub } = getClients()\n const { data, error } = await pub.rpc('inventory_correct_usage_batch', {\n p_reason: input.reason,\n // The order the lines travel in is the order they were typed in, and\n // the RPC stores it as line_no — reading the batch back later shows\n // the conference as it happened.\n p_lines: input.lines.map((l) => ({\n item_id: l.itemId, product_id: l.productId, quantity: l.quantity,\n })),\n })\n if (error) throw new Error(error.message)\n return {\n operationId: (data as any)?.operation_id ?? undefined,\n linesApplied: Number((data as any)?.lines_applied ?? 0),\n linesUnchanged: Number((data as any)?.lines_unchanged ?? 0),\n }\n },\n\n // --- Summary ---\n async getSummary(): Promise<InventorySummary> {\n const { core, pub } = getClients()\n const { data: products } = await core.from(PRODUCTS_READ).select('stock, min_stock, price, is_active').eq('is_active', true)\n const items = products ?? []\n const lowStock = items.filter((p: any) => p.stock > 0 && p.stock <= (p.min_stock ?? 0))\n const outOfStock = items.filter((p: any) => p.stock <= 0)\n const totalValue = items.reduce((sum: number, p: any) => sum + (p.stock ?? 0) * (p.price ?? 0), 0)\n\n const weekAgo = new Date()\n weekAgo.setDate(weekAgo.getDate() - 7)\n const { data: movements } = await pub.from(T.stockMovements).select('movement_type').gte('movement_date', weekAgo.toISOString().slice(0, 10))\n const movs = movements ?? []\n const movementsByType: Record<MovementType, number> = { entry: 0, exit: 0, adjustment: 0, transfer: 0, loss: 0 }\n for (const m of movs) movementsByType[m.movement_type as MovementType]++\n\n return {\n totalProducts: items.length,\n lowStockCount: lowStock.length,\n outOfStockCount: outOfStock.length,\n totalStockValue: totalValue,\n recentMovementCount: movs.length,\n movementsByType,\n }\n },\n }\n\n return provider\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { dedup } from '@fayz-ai/admin'\nimport { toast } from '@fayz-ai/ui'\nimport type { InventoryDataProvider } from './data/types'\nimport type {\n Product, StockMovement, StockLocation, Recipe,\n InventorySummary, ProductQuery, MovementQuery,\n UsageAuditEntry, UsageAuditQuery, UsageAuditCorrection, UsageAuditBatchResult,\n CreateProductInput, CreateStockMovementInput, CreateRecipeInput,\n} from './types'\n\nexport interface InventoryUIState {\n products: Product[]\n productsTotal: number\n productsLoading: boolean\n productQuery: ProductQuery\n\n movements: StockMovement[]\n movementsTotal: number\n movementsLoading: boolean\n\n usageAudit: UsageAuditEntry[]\n usageAuditTotal: number\n usageAuditLoading: boolean\n usageAuditQuery: UsageAuditQuery\n\n locations: StockLocation[]\n locationsLoading: boolean\n\n recipes: Recipe[]\n recipesLoading: boolean\n\n summary: InventorySummary | null\n summaryLoading: boolean\n\n fetchSummary(): Promise<void>\n fetchProducts(query: ProductQuery): Promise<void>\n fetchMovements(query: MovementQuery): Promise<void>\n fetchUsageAudit(query: UsageAuditQuery): Promise<void>\n correctUsage(input: { itemId: string; productId: string; quantity: number; reason: string }): Promise<void>\n correctUsageBatch(input: { reason: string; lines: UsageAuditCorrection[] }): Promise<UsageAuditBatchResult>\n fetchLocations(): Promise<void>\n fetchRecipes(): Promise<void>\n createProduct(input: CreateProductInput): Promise<Product>\n createMovement(input: CreateStockMovementInput): Promise<StockMovement>\n createRecipe(input: CreateRecipeInput): Promise<Recipe>\n}\n\nexport function createInventoryStore(provider: InventoryDataProvider): StoreApi<InventoryUIState> {\n return createStore<InventoryUIState>((set, get) => ({\n products: [], productsTotal: 0, productsLoading: false, productQuery: {},\n movements: [], movementsTotal: 0, movementsLoading: false,\n usageAudit: [], usageAuditTotal: 0, usageAuditLoading: false, usageAuditQuery: {},\n locations: [], locationsLoading: false,\n recipes: [], recipesLoading: false,\n summary: null, summaryLoading: false,\n\n async fetchSummary() {\n return dedup('inv:summary', async () => {\n set({ summaryLoading: true })\n const summary = await provider.getSummary()\n set({ summary, summaryLoading: false })\n })\n },\n\n async fetchProducts(query) {\n const key = 'inv:products:' + JSON.stringify(query)\n return dedup(key, async () => {\n set({ productsLoading: true, productQuery: query })\n const result = await provider.getProducts(query)\n set({ products: result.data, productsTotal: result.total, productsLoading: false })\n })\n },\n\n async fetchMovements(query) {\n return dedup('inv:movements:' + JSON.stringify(query), async () => {\n set({ movementsLoading: true })\n const result = await provider.getMovements(query)\n set({ movements: result.data, movementsTotal: result.total, movementsLoading: false })\n })\n },\n\n async fetchUsageAudit(query) {\n return dedup('inv:usage-audit:' + JSON.stringify(query), async () => {\n set({ usageAuditLoading: true, usageAuditQuery: query })\n try {\n const result = await provider.getUsageAudit(query)\n set({ usageAudit: result.data, usageAuditTotal: result.total, usageAuditLoading: false })\n } catch (err) {\n // Leaving the flag on would keep the skeleton in place forever, and a\n // permanent skeleton reads as \"still loading\", never as \"it failed\".\n set({ usageAuditLoading: false })\n throw err\n }\n })\n },\n\n async correctUsage(input) {\n await provider.correctUsage(input)\n const [result, summary] = await Promise.all([\n provider.getUsageAudit(get().usageAuditQuery),\n provider.getSummary(),\n ])\n set({ usageAudit: result.data, usageAuditTotal: result.total, summary })\n },\n\n async correctUsageBatch(input) {\n const outcome = await provider.correctUsageBatch(input)\n // The list that shows the state reloads after acting, or the screen keeps\n // showing the quantities the batch just moved.\n const [result, summary] = await Promise.all([\n provider.getUsageAudit(get().usageAuditQuery),\n provider.getSummary(),\n ])\n set({ usageAudit: result.data, usageAuditTotal: result.total, summary })\n return outcome\n },\n\n async fetchLocations() {\n return dedup('inv:locations', async () => {\n set({ locationsLoading: true })\n const locations = await provider.getLocations()\n set({ locations, locationsLoading: false })\n })\n },\n\n async fetchRecipes() {\n set({ recipesLoading: true })\n const recipes = await provider.getRecipes()\n set({ recipes, recipesLoading: false })\n },\n\n async createProduct(input) {\n try {\n const product = await provider.createProduct(input)\n const query = get().productQuery\n const [result, summary] = await Promise.all([provider.getProducts(query), provider.getSummary()])\n set({ products: result.data, productsTotal: result.total, summary })\n toast.success('Product created')\n return product\n } catch (err: any) {\n toast.error('Failed to create product', { description: err?.message })\n throw err\n }\n },\n\n async createMovement(input) {\n try {\n const movement = await provider.createMovement(input)\n const [summary] = await Promise.all([provider.getSummary()])\n set({ summary })\n toast.success('Stock movement recorded')\n return movement\n } catch (err: any) {\n toast.error('Failed to record movement', { description: err?.message })\n throw err\n }\n },\n\n async createRecipe(input) {\n try {\n const recipe = await provider.createRecipe(input)\n const recipes = await provider.getRecipes()\n set({ recipes })\n toast.success('Recipe created')\n return recipe\n } catch (err: any) {\n toast.error('Failed to create recipe', { description: err?.message })\n throw err\n }\n },\n }))\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { T } from './tables'\n\nconst supplierEntity: EntityDef = {\n name: 'Supplier',\n namePlural: 'Suppliers',\n icon: 'Building2',\n layout: 'person',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, searchable: true },\n { key: 'phone', label: 'Phone', type: 'phone', showInTable: true },\n { key: 'email', label: 'Email', type: 'email', showInTable: true },\n { key: 'documentNumber', label: 'Tax ID', type: 'text', showInTable: true },\n // No address field: a supplier has as many as the operation needs (the\n // office that invoices, the warehouse the goods leave from). `layout:\n // 'person'` gives the record an \"Addresses\" tab backed by public.addresses,\n // which is the same relation clients and patients already use.\n { key: 'notes', label: 'Notes', type: 'textarea' },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: {\n table: 'people',\n tenantScoped: true,\n filters: { kind: 'supplier' },\n defaults: { kind: 'supplier' },\n },\n}\n\nconst measurementUnitEntity: EntityDef = {\n name: 'Measurement Unit',\n namePlural: 'Measurement Units',\n icon: 'Ruler',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'abbreviation', label: 'Abbreviation', type: 'text', required: true, showInTable: true },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.measurementUnits, tenantScoped: true },\n}\n\nconst productCategoryEntity: EntityDef = {\n name: 'Product Category',\n namePlural: 'Product Categories',\n icon: 'Tag',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'parentId', label: 'Parent', type: 'text', showInTable: false },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.productCategories, tenantScoped: true },\n}\n\nconst stockLocationEntity: EntityDef = {\n name: 'Stock Location',\n namePlural: 'Stock Locations',\n icon: 'Warehouse',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },\n { key: 'description', label: 'Description', type: 'textarea', showInTable: true },\n { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },\n ],\n data: { table: T.stockLocations, tenantScoped: true },\n}\n\nexport const inventoryRegistries: PluginRegistryDef[] = [\n // --- Editable ---\n {\n id: 'suppliers',\n entity: supplierEntity,\n icon: 'Building2',\n description: 'Manage your product and material suppliers',\n display: 'table',\n },\n {\n id: 'product-categories',\n entity: productCategoryEntity,\n icon: 'Tag',\n description: 'Product categories for organization',\n display: 'table',\n },\n {\n id: 'stock-locations',\n entity: stockLocationEntity,\n icon: 'Warehouse',\n description: 'Physical storage locations for inventory',\n display: 'table',\n },\n // --- Seeded defaults, still editable by the tenant ---\n {\n id: 'measurement-units',\n entity: measurementUnitEntity,\n icon: 'Ruler',\n description: 'Standard units of measure',\n display: 'table',\n seedData: [\n { id: 'mu-unit', name: 'Unit', abbreviation: 'un', isActive: true },\n { id: 'mu-box', name: 'Box', abbreviation: 'box', isActive: true },\n { id: 'mu-kg', name: 'Kilogram', abbreviation: 'kg', isActive: true },\n { id: 'mu-g', name: 'Gram', abbreviation: 'g', isActive: true },\n { id: 'mu-l', name: 'Liter', abbreviation: 'L', isActive: true },\n { id: 'mu-ml', name: 'Milliliter', abbreviation: 'mL', isActive: true },\n ],\n },\n]\n","import type { SetupGuideDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Como o Estoque entra em pé.\n//\n// A ordem aqui não é preferência, é dependência dura: unidade de medida →\n// local → produto → saldo. Quem cadastra o produto antes de ter local e\n// unidade acaba com um catálogo bonito e saldo nenhum, e a conclusão errada\n// (\"o estoque não funciona\") é sempre a mesma.\n//\n// A outra coisa que estes guias existem para dizer: o estoque deste produto é\n// um RAZÃO append-only. Nada se apaga; corrigir é lançar a diferença. É a\n// regra que mais surpreende quem vem de planilha.\n// ---------------------------------------------------------------------------\n\nconst SETTINGS = '/settings/inventory'\n\nconst foundations: SetupGuideDef = {\n feature: 'inventory.cadastros-base',\n title: 'Cadastros do Estoque',\n about:\n 'As quatro listas de trás — unidades de medida, locais, categorias e fornecedores — sem as quais o cadastro de produto não tem o que escolher.',\n route: `${SETTINGS}/stock-locations`,\n step: 'inventory.foundations',\n requires: [],\n steps: [\n {\n do: 'Configurações › Estoque › Unidades de medida: confira o que já vem (un, cx, kg, g, L, mL) e acrescente o que a casa usa.',\n route: `${SETTINGS}/measurement-units`,\n },\n {\n do: 'Locais de estoque: cadastre onde as coisas ficam de verdade — \"Sala 2\", \"Depósito\", \"Bancada\".',\n why: 'Saldo é sempre de um produto NUM local. Sem local não existe saldo.',\n route: `${SETTINGS}/stock-locations`,\n },\n { do: 'Categorias: poucas e grandes. Elas são para achar, não para classificar contabilmente.', route: `${SETTINGS}/product-categories` },\n { do: 'Fornecedores: só os que você compra de verdade.', route: `${SETTINGS}/suppliers` },\n ],\n rules: [\n 'Local de estoque não é unidade da rede. Uma unidade pode ter vários locais; um local pertence a uma unidade.',\n ],\n pitfalls: [\n 'Pular os locais e cadastrar produto: o produto existe, o saldo não tem onde morar, e a tela parece quebrada.',\n ],\n answers: [\n 'Por onde eu começo no estoque?',\n 'Onde cadastro os lugares onde guardo as coisas?',\n 'Como crio uma unidade de medida?',\n ],\n next: ['inventory.produtos'],\n}\n\nconst products: SetupGuideDef = {\n feature: 'inventory.produtos',\n title: 'Produtos',\n about:\n 'O catálogo do que a casa guarda, vende e consome. Um produto diz em que unidade ele é contado e quanto custa — e é isso que faz o resto do estoque ter sentido.',\n route: '/inventory/products/list',\n step: 'inventory.catalog',\n requires: [\n {\n title: 'Unidades de medida e categorias',\n feature: 'inventory.cadastros-base',\n route: `${SETTINGS}/measurement-units`,\n check: 'o formulário de produto oferece unidade e categoria para escolher',\n },\n {\n title: 'Locais de estoque',\n feature: 'inventory.cadastros-base',\n route: `${SETTINGS}/stock-locations`,\n check: 'existe pelo menos um local — é onde o saldo vai morar',\n },\n ],\n steps: [\n { do: 'Estoque › Produtos › Novo.', route: '/inventory/products/new' },\n {\n do: 'Escolha a unidade em que você CONTA o produto, não a que o fornecedor vende.',\n why: 'Se você conta ampolas e ele vende caixa, o produto é em ampola — a conversão é problema da entrada.',\n },\n { do: 'Defina o estoque mínimo do que não pode faltar; é o que gera aviso.' },\n { do: 'Depois de salvar, dê a entrada inicial para o produto passar a ter saldo.', route: '/inventory/stock/entry' },\n ],\n rules: [\n 'Cadastrar produto NÃO cria saldo. Saldo só nasce de um movimento de entrada.',\n 'Trocar a unidade de medida de um produto que já tem movimento reinterpreta o histórico inteiro. Crie outro produto em vez disso.',\n ],\n answers: [\n 'Como cadastro meus produtos?',\n 'Cadastrei o produto e o estoque está zerado',\n 'Como configuro o estoque mínimo?',\n ],\n next: ['inventory.movimentacoes'],\n}\n\nconst movements: SetupGuideDef = {\n feature: 'inventory.movimentacoes',\n title: 'Entradas e Saídas',\n about:\n 'Tudo que entra e sai, com data, quem fez e por quê. É o razão do estoque: o saldo de hoje é a soma disto, não um número que alguém digita.',\n route: '/inventory/stock/entry',\n requires: [\n {\n title: 'Produtos cadastrados',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'dá para escolher um produto no movimento',\n },\n {\n title: 'Local de estoque',\n feature: 'inventory.cadastros-base',\n route: `${SETTINGS}/stock-locations`,\n check: 'o movimento pede um local e existe opção',\n },\n ],\n steps: [\n { do: 'Estoque › Movimentações › Entrada para a compra que chegou.', route: '/inventory/stock/entry' },\n { do: 'Saída para o que foi descartado, perdido ou usado fora de um atendimento.', route: '/inventory/stock/exit' },\n { do: 'O histórico mostra tudo, inclusive o que o sistema lançou sozinho.', route: '/inventory/stock/history' },\n ],\n rules: [\n 'O razão é append-only: nada é apagado. Corrigir é lançar o movimento contrário — e o histórico guarda os dois.',\n 'Venda concluída baixa estoque sozinha. O que aparecer no histórico sem ninguém ter lançado veio daí.',\n ],\n pitfalls: [\n 'Ajustar saldo \"editando o produto\". Não existe: saldo só muda por movimento.',\n ],\n answers: [\n 'Como dou entrada numa compra?',\n 'Como corrijo um lançamento errado?',\n 'De onde vieram essas saídas que eu não lancei?',\n ],\n next: ['inventory.contagem', 'inventory.auditoria-de-uso'],\n}\n\nconst usageAudit: SetupGuideDef = {\n feature: 'inventory.auditoria-de-uso',\n title: 'Auditoria de Uso',\n about:\n 'O que os atendimentos consumiram de verdade, lado a lado com o que era o padrão. Serve para achar o consumo que fugiu — e para corrigir a quantidade lançada errada.',\n route: '/inventory/stock/usage/audit',\n requires: [\n {\n title: 'Atendimentos concluídos que consumiram material',\n check: 'a lista traz linhas; vazia quer dizer que nada foi consumido no período, não que a tela esteja quebrada',\n },\n {\n title: 'Produtos com custo preenchido',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'a coluna de custo mostra valor',\n required: false,\n },\n ],\n steps: [\n { do: 'Estoque › Auditoria de uso e escolha o período.', route: '/inventory/stock/usage/audit' },\n { do: 'Compare o consumido com o padrão do serviço; olhe o que está fora da curva.' },\n { do: 'Corrija a linha quando a quantidade tiver sido lançada errada.' },\n ],\n rules: [\n 'Aqui é DEPOIS da baixa, não antes: o atendimento já consumiu. A pergunta é \"foi isso mesmo?\", e a ação é Corrigir.',\n 'Corrigir LANÇA a diferença no razão — não reescreve o movimento antigo.',\n ],\n answers: [\n 'O consumo do salão está alto, onde vejo?',\n 'A quantidade foi lançada errada, dá para arrumar?',\n 'Isto aprova a baixa de estoque?',\n ],\n}\n\nconst counts: SetupGuideDef = {\n feature: 'inventory.contagem',\n title: 'Contagem de Estoque',\n about:\n 'O inventário: conta-se o que existe na prateleira e o sistema lança a diferença contra o que ele achava que tinha.',\n route: '/inventory/stock/counts',\n requires: [\n {\n title: 'Produtos com saldo',\n feature: 'inventory.movimentacoes',\n route: '/inventory/stock/history',\n check: 'os produtos já têm entrada lançada — contar contra saldo zero não mede nada',\n },\n ],\n steps: [\n { do: 'Estoque › Contagens › Nova, escolhendo o local a contar.', route: '/inventory/stock/counts/new' },\n { do: 'Conte de verdade e registre o que achou, item por item.' },\n { do: 'Feche a sessão: a diferença vira movimento de ajuste com o motivo \"contagem\".' },\n ],\n rules: [\n 'A contagem é por LOCAL. Contar meio depósito e fechar a sessão zera o que não foi contado.',\n ],\n answers: [\n 'Como faço inventário?',\n 'Como acerto o estoque com o que tem na prateleira?',\n ],\n}\n\nconst recipes: SetupGuideDef = {\n feature: 'inventory.receitas',\n title: 'Receitas',\n about:\n 'A fórmula do que a casa produz: quanto de cada insumo vira um produto final. Produzir consome os ingredientes e cria o produto, num movimento só.',\n route: '/inventory/recipes/list',\n requires: [\n {\n title: 'Ingredientes e produto final cadastrados',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'os dois lados da receita existem no catálogo',\n },\n ],\n steps: [\n { do: 'Estoque › Receitas › Nova.', route: '/inventory/recipes/new' },\n { do: 'Diga o que ela PRODUZ e em que quantidade.' },\n { do: 'Liste os ingredientes com a quantidade de cada um, na unidade em que eles são contados.' },\n ],\n rules: [\n 'Produzir por receita é um movimento duplo: saída dos insumos, entrada do produto final. Os dois ficam no histórico.',\n ],\n answers: [\n 'Como cadastro uma fórmula?',\n 'Produzo internamente, como controlo?',\n ],\n}\n\nexport const inventorySetupGuides: SetupGuideDef[] = [\n foundations,\n products,\n movements,\n counts,\n usageAudit,\n recipes,\n]\n","import { countByTenant, type OnboardingProgramDef } from '@fayz-ai/core'\nimport { T } from '../data/tables'\n\n/**\n * Implantação do Estoque — e a ordem aqui é dependência, não gosto.\n *\n * Local antes de produto, produto antes de saldo. Quem cadastra o catálogo\n * primeiro termina com produto sem lugar onde ter saldo, conclui que \"o\n * estoque não funciona\" e desiste na primeira semana. Este programa existe\n * principalmente para impedir essa sequência.\n */\nexport function buildInventoryOnboarding(): OnboardingProgramDef {\n return {\n id: 'inventory',\n title: 'Seu estoque de pé',\n order: 60,\n role: 'operations',\n instructions: `Você está implantando o ESTOQUE. A ordem é dependência dura, não preferência: local → produto → saldo.\n\n- Comece pelos LOCAIS. Sem local não existe saldo, e produto cadastrado antes disso não tem onde ter quantidade. Se a pessoa quiser pular para produtos, explique isso em uma linha e siga com ela mesmo assim — mas volte.\n- Unidade de medida é a que a casa CONTA, não a que o fornecedor vende. Pergunte assim: \"quando você olha a prateleira, você conta o quê?\".\n- Cadastrar produto não cria saldo. Diga isso ANTES de a pessoa cadastrar dez produtos e estranhar o zero.\n- O razão é append-only: nada é apagado, corrigir é lançar a diferença. É a regra que mais surpreende quem vem de planilha — diga uma vez, quando aparecer a primeira correção.\n- Cada passo tem um guia (\\`readSetupGuide\\`) com as armadilhas. Leia antes de conduzir.`,\n steps: [\n {\n key: 'foundations',\n title: 'Diga onde as coisas ficam',\n description: 'Sala, depósito, bancada — saldo é sempre de um produto NUM lugar.',\n icon: 'Warehouse',\n route: '/settings/inventory/stock-locations',\n priority: 'high',\n agentHint:\n 'Pergunte onde as coisas ficam guardadas de verdade e use as palavras da pessoa. Dois ou três locais bastam para começar.',\n howTo:\n 'Configurações › Estoque › Locais de estoque. Cadastre os lugares reais onde o material fica — \"Sala 2\", \"Depósito\", \"Bancada\". Saldo é sempre de um produto num local: sem isso, o produto existe e a quantidade não tem onde morar.',\n celebrate: 'Cada coisa no seu lugar 📦',\n script: [\n { kind: 'say', text: 'Estoque começa pelo lugar: onde as coisas ficam guardadas.' },\n { kind: 'goto', route: '/settings/inventory/stock-locations' },\n {\n kind: 'ask',\n text: 'Estamos em Locais de estoque. Pergunte onde o material fica guardado na casa e cadastre com as palavras da própria pessoa.',\n },\n ],\n check: async () => (await countByTenant(T.stockLocations)) > 0,\n },\n {\n key: 'catalog',\n title: 'Traga o que você guarda',\n description: 'O catálogo do que a casa usa e vende, na unidade em que você conta.',\n icon: 'Package',\n route: '/inventory/products/list',\n priority: 'high',\n replaces: 'catalog',\n agentHint:\n 'Pergunte onde o catálogo está hoje (planilha, nota do fornecedor, cabeça). Um produto já destrava o resto — não espere pelos duzentos.',\n howTo:\n 'Estoque › Produtos › Novo. Escolha a unidade em que VOCÊ conta o produto (se você conta ampola e o fornecedor vende caixa, é ampola). Defina o estoque mínimo do que não pode faltar. Cadastrar não cria saldo — o saldo vem da entrada, no passo seguinte.',\n celebrate: 'Catálogo no ar 🎉',\n check: async () => (await countByTenant('products')) > 0,\n },\n {\n key: 'first-entry',\n title: 'Dê a primeira entrada',\n description: 'É o movimento que faz o saldo existir.',\n icon: 'ArrowDownToLine',\n route: '/inventory/stock/entry',\n agentHint:\n 'Faça junto com um produto só, para a pessoa VER o saldo aparecer. É o momento em que o módulo deixa de ser abstrato.',\n howTo:\n 'Estoque › Movimentações › Entrada. Escolha o produto, o local e a quantidade que você tem hoje na prateleira. O saldo aparece na hora, e o lançamento fica no histórico com data e autor — nada aqui é apagado depois; corrigir é lançar a diferença.',\n celebrate: 'Saldo na mão 📈',\n script: [\n { kind: 'say', text: 'Agora o que faz o saldo existir: uma entrada.' },\n { kind: 'goto', route: '/inventory/stock/entry' },\n { kind: 'await', text: 'Escolha um produto, o local e a quantidade que tem hoje. Eu vejo daqui quando entrar.' },\n ],\n check: async () => (await countByTenant(T.stockMovements)) > 0,\n },\n ],\n }\n}\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const en: Record<string, string> = {\n \"inventory.dashboard.activeItems\": \"Active items\",\n \"inventory.dashboard.belowMinimum\": \"Below minimum\",\n \"inventory.dashboard.entries\": \"Entries:\",\n \"inventory.dashboard.exits\": \"Exits:\",\n \"inventory.dashboard.last7Days\": \"Last 7 days\",\n \"inventory.dashboard.lowStock\": \"Low Stock\",\n \"inventory.dashboard.needRestocking\": \"Need restocking\",\n \"inventory.dashboard.outOfStock\": \"Out of Stock\",\n \"inventory.dashboard.quickActions\": \"Quick Actions\",\n \"inventory.dashboard.quickActionsDesc\": \"Use the sidebar to record stock entries, exits, or manage products.\",\n \"inventory.dashboard.recentActivity\": \"Recent Activity\",\n \"inventory.dashboard.stockValue\": \"Stock Value\",\n \"inventory.dashboard.totalProducts\": \"Total Products\",\n \"inventory.dashboard.totalValue\": \"Total inventory value\",\n \"inventory.history.noMovements\": \"No movements recorded\",\n \"inventory.history.columnDate\": \"Date\",\n \"inventory.history.columnProduct\": \"Product\",\n \"inventory.history.columnType\": \"Type\",\n \"inventory.history.columnLocation\": \"Location\",\n \"inventory.history.columnQty\": \"Qty\",\n \"inventory.history.columnTotal\": \"Total\",\n \"inventory.history.newEntry\": \"New entry\",\n \"inventory.history.newExit\": \"Exit\",\n \"inventory.nav.recipes\": \"Recipes\",\n \"registry.suppliers\": \"Suppliers\",\n \"registry.suppliers.description\": \"Who you buy from\",\n \"registry.product-categories\": \"Categories\",\n \"registry.product-categories.description\": \"How the catalogue is grouped\",\n \"registry.stock-locations\": \"Stock locations\",\n \"registry.stock-locations.description\": \"Where stock physically sits — cold room, dry store, freezer\",\n \"registry.measurement-units\": \"Units of measure\",\n \"registry.measurement-units.description\": \"How each item is counted\",\n \"inventory.history.searchPlaceholder\": \"Search movements...\",\n \"inventory.history.subtitle\": \"All stock movements\",\n \"inventory.history.title\": \"Stock History\",\n \"inventory.nav.dashboard\": \"Dashboard\",\n \"inventory.nav.entry\": \"Entry\",\n \"inventory.nav.exit\": \"Exit\",\n \"inventory.nav.history\": \"History\",\n \"inventory.nav.list\": \"List\",\n \"inventory.nav.new\": \"New\",\n \"inventory.nav.products\": \"Products\",\n \"inventory.nav.stock\": \"Stock\",\n \"inventory.page.newProduct\": \"New Product\",\n \"inventory.page.newProductDesc\": \"Add a product to your catalog\",\n \"inventory.page.settingsSubtitle\": \"Preferences, suppliers, categories, and units\",\n \"inventory.page.settingsTitle\": \"Inventory Settings\",\n \"inventory.page.stockEntry\": \"Stock Entry\",\n \"inventory.page.stockEntryDesc\": \"Record goods received\",\n \"inventory.page.stockExit\": \"Stock Exit\",\n \"inventory.page.stockExitDesc\": \"Record goods used or sold\",\n \"inventory.recipeDetail.active\": \"Active\",\n \"inventory.recipeDetail.backToList\": \"Back to list\",\n \"inventory.recipeDetail.inactive\": \"Inactive\",\n \"inventory.recipeDetail.ingredientCount\": \"Ingredients\",\n \"inventory.recipeDetail.ingredientsTitle\": \"Ingredients\",\n \"inventory.recipeDetail.instructions\": \"Instructions\",\n \"inventory.recipeDetail.noIngredients\": \"No ingredients defined\",\n \"inventory.recipeDetail.notFound\": \"Recipe not found\",\n \"inventory.recipeDetail.prepTime\": \"Prep time\",\n \"inventory.recipeDetail.produces\": \"Produces\",\n \"inventory.recipeDetail.recipes\": \"Recipes\",\n \"inventory.recipeDetail.yield\": \"Yield\",\n \"inventory.recipes.createFirst\": \"Create your first recipe\",\n \"inventory.recipes.ingredients\": \"Ingredients\",\n \"inventory.recipes.newRecipe\": \"New Recipe\",\n \"inventory.recipes.noRecipes\": \"No recipes yet\",\n \"inventory.recipes.produces\": \"Produces:\",\n \"inventory.recipes.productionFormulas\": \"{{count}} production formulas\",\n \"inventory.recipes.recipesDesc\": \"Recipes define how to produce products from ingredients\",\n \"inventory.recipes.title\": \"Recipes\",\n \"inventory.recipes.yield\": \"Yield\",\n \"inventory.stock.additionalDetails\": \"Additional details (optional)\",\n \"inventory.stock.adjustmentDesc\": \"Count correction\",\n \"inventory.stock.adjustmentLabel\": \"Adjustment\",\n \"inventory.stock.back\": \"Back\",\n \"inventory.stock.batchNumber\": \"Batch Number\",\n \"inventory.stock.currentStock\": \"Current Stock\",\n \"inventory.stock.destination\": \"Destination\",\n \"inventory.stock.document\": \"Document\",\n \"inventory.stock.documentNumber\": \"Document Number\",\n \"inventory.stock.entry\": \"Stock Entry\",\n \"inventory.stock.entryDesc\": \"Receiving goods\",\n \"inventory.stock.entryLabel\": \"Entry\",\n \"inventory.stock.exit\": \"Stock Exit\",\n \"inventory.stock.exitDesc\": \"Using or selling\",\n \"inventory.stock.exitLabel\": \"Exit\",\n \"inventory.stock.expirationDate\": \"Expiration Date\",\n \"inventory.stock.fromLocation\": \"From Location\",\n \"inventory.stock.locationLabel\": \"Location\",\n \"inventory.stock.lossDesc\": \"Waste or damage\",\n \"inventory.stock.lossLabel\": \"Loss\",\n \"inventory.stock.movement\": \"Stock Movement\",\n \"inventory.stock.movementDetails\": \"Movement Details\",\n \"inventory.stock.movementType\": \"Movement type\",\n \"inventory.stock.next\": \"Next\",\n \"inventory.stock.notes\": \"Notes\",\n \"inventory.stock.product\": \"Product\",\n \"inventory.stock.quantity\": \"Quantity *\",\n \"inventory.stock.quantityLabel\": \"Quantity\",\n \"inventory.stock.reason\": \"Reason *\",\n \"inventory.stock.reasonLabel\": \"Reason\",\n \"inventory.stock.recordMovement\": \"Record Movement\",\n \"inventory.stock.recorded\": \"Recorded\",\n \"inventory.stock.recording\": \"Recording...\",\n \"inventory.stock.searchProduct\": \"Search by name, SKU, or barcode...\",\n \"inventory.stock.stepOf\": \"Step {{step}} of 3\",\n \"inventory.stock.supplier\": \"Supplier\",\n \"inventory.stock.toLocation\": \"To Location *\",\n \"inventory.stock.total\": \"Total\",\n \"inventory.stock.totalCost\": \"Total Cost\",\n \"inventory.stock.transferDesc\": \"Between locations\",\n \"inventory.stock.transferLabel\": \"Transfer\",\n \"inventory.stock.unitCost\": \"Unit Cost\",\n \"inventory.stock.unitCostLabel\": \"Unit Cost\",\n \"inventory.stock.searchSupplier\": \"Search supplier...\",\n \"inventory.stock.noSuppliers\": \"No supplier registered\",\n \"inventory.productDetail.stockTab\": \"Stock\",\n \"inventory.productDetail.positionsTitle\": \"Stock by location\",\n \"inventory.productDetail.onHand\": \"On hand\",\n \"inventory.productDetail.noPositions\": \"No stock in any location\",\n \"inventory.productDetail.historyTitle\": \"Movement history\",\n \"inventory.productDetail.undoLast\": \"Undo last movement\",\n \"inventory.productDetail.undoTitle\": \"Undo the last movement?\",\n \"inventory.productDetail.undoDescription\": \"{{type}} of {{quantity}} on {{date}} leaves the history, and the stock it moved goes back.\",\n \"inventory.productDetail.undoConfirm\": \"Undo\",\n \"inventory.productDetail.undone\": \"Movement undone\",\n \"inventory.productDetail.undoFailed\": \"Could not undo the movement\",\n \"inventory.productDetail.notFound\": \"Product not found\",\n \"inventory.productDetail.backToList\": \"Back to products\",\n \"inventory.onboarding.welcome\": \"Welcome to Inventory\",\n \"inventory.onboarding.description\": \"Track products, manage stock levels, and monitor movements across your business.\",\n \"inventory.onboarding.skip\": \"Skip setup\",\n \"inventory.onboarding.getStarted\": \"Get Started\",\n \"inventory.onboarding.units.title\": \"Measurement Units\",\n \"inventory.onboarding.units.description\": \"Default units (Unit, Box, Kg, L, etc.) are ready. Customize them anytime in Settings.\",\n \"inventory.onboarding.locations.title\": \"Stock Locations\",\n \"inventory.onboarding.locations.description\": \"A default storage location has been created. Add more for multi-location tracking.\",\n \"inventory.onboarding.start\": \"Start using Inventory\",\n \"inventory.onboarding.preparing\": \"Preparing inventory...\",\n \"inventory.onboarding.setupError\": \"We could not prepare the default units and stock location. Try again.\",\n \"inventory.quickActions.newProduct\": \"New Product\",\n \"inventory.quickActions.newProductDesc\": \"Add a product to your catalog\",\n \"inventory.quickActions.stockEntry\": \"Stock Entry\",\n \"inventory.quickActions.stockEntryDesc\": \"Record goods received\",\n \"inventory.quickActions.stockExit\": \"Stock Exit\",\n \"inventory.quickActions.stockExitDesc\": \"Record goods used or sold\",\n \"inventory.settingsPage.title\": \"Inventory Settings\",\n \"inventory.settingsPage.subtitle\": \"Manage units, categories, and stock locations\",\n \"inventory.settings.stockManagement\": \"Stock Management\",\n \"inventory.settings.stockManagementDesc\": \"How stock levels are tracked\",\n \"inventory.settings.lowStockAlerts\": \"Low stock alerts\",\n \"inventory.settings.lowStockAlertsDesc\": \"Show warnings when products fall below minimum quantity\",\n \"inventory.settings.requireReason\": \"Require reason for adjustments\",\n \"inventory.settings.requireReasonDesc\": \"Make reason mandatory for stock adjustments and losses\",\n \"inventory.settings.autoDeduct\": \"Auto-deduct on service\",\n \"inventory.settings.autoDeductDesc\": \"Automatically deduct products when a service is executed\",\n \"inventory.settings.products\": \"Products\",\n \"inventory.settings.productsDesc\": \"Product catalog behavior\",\n \"inventory.settings.requireSku\": \"Require SKU\",\n \"inventory.settings.requireSkuDesc\": \"Make SKU mandatory when creating products\",\n \"inventory.settings.allowNegative\": \"Allow negative stock\",\n \"inventory.settings.allowNegativeDesc\": \"Allow stock quantities to go below zero\",\n \"inventory.settings.notifications\": \"Notifications\",\n \"inventory.settings.notificationsDesc\": \"Alerts and reminders\",\n \"inventory.settings.lowStockEmail\": \"Low stock email alerts\",\n \"inventory.settings.lowStockEmailDesc\": \"Send email when products reach minimum quantity\",\n \"inventory.settings.expiryWarnings\": \"Expiry date warnings\",\n \"inventory.settings.expiryWarningsDesc\": \"Alert before products expire (batch tracking)\",\n \"inventory.productForm.newProduct\": \"New Product\",\n \"inventory.productForm.editProduct\": \"Edit Product\",\n \"inventory.productForm.updateDetails\": \"Update product details\",\n \"inventory.productForm.addToCatalog\": \"Add a product to your catalog\",\n \"inventory.productForm.cancel\": \"Cancel\",\n \"inventory.productForm.save\": \"Save\",\n \"inventory.productForm.saving\": \"Saving...\",\n \"inventory.productForm.generalInfo\": \"General Information\",\n \"inventory.productForm.name\": \"Name\",\n \"inventory.productForm.namePlaceholder\": \"Product name\",\n \"inventory.productForm.brand\": \"Brand\",\n \"inventory.productForm.brandPlaceholder\": \"Brand name\",\n \"inventory.productForm.sku\": \"SKU\",\n \"inventory.productForm.skuPlaceholder\": \"Internal code\",\n \"inventory.productForm.barcode\": \"Barcode\",\n \"inventory.productForm.barcodePlaceholder\": \"EAN / UPC\",\n \"inventory.productForm.description\": \"Description\",\n \"inventory.productForm.descriptionPlaceholder\": \"Additional information about the product\",\n \"inventory.productForm.classification\": \"Classification\",\n \"inventory.productForm.classificationDesc\": \"How this product is used in your business\",\n \"inventory.productForm.typeIngredient\": \"Raw material used in production or services\",\n \"inventory.productForm.typeSale\": \"Sold directly to customers\",\n \"inventory.productForm.typeIntermediate\": \"Produced internally from other items\",\n \"inventory.productForm.typeAsset\": \"Fixed asset for patrimony tracking\",\n \"inventory.productForm.pricing\": \"Pricing\",\n \"inventory.productForm.costPrice\": \"Cost Price\",\n \"inventory.productForm.salePrice\": \"Sale Price\",\n \"inventory.productForm.margin\": \"Margin\",\n \"inventory.productForm.stockLevels\": \"Stock Levels\",\n \"inventory.productForm.stockLevelsDesc\": \"Minimum and maximum thresholds for alerts\",\n \"inventory.productForm.minQuantity\": \"Minimum Quantity\",\n \"inventory.productForm.minQuantityHint\": \"Alert when stock falls below this\",\n \"inventory.productForm.maxQuantity\": \"Maximum Quantity\",\n \"inventory.productForm.maxQuantityHint\": \"Max capacity for this product\",\n \"inventory.productForm.optional\": \"Optional\",\n \"inventory.productForm.organization\": \"Organisation\",\n \"inventory.productForm.organizationDesc\": \"Category, unit, supplier and default storage location\",\n \"inventory.productForm.category\": \"Category\",\n \"inventory.productForm.measurementUnit\": \"Unit of measure\",\n \"inventory.productForm.measurementUnitHint\": \"How this item is counted in stock\",\n \"inventory.productForm.supplier\": \"Default supplier\",\n \"inventory.productForm.defaultLocation\": \"Default location\",\n \"inventory.movementType.entry\": \"Entry\",\n \"inventory.movementType.exit\": \"Exit\",\n \"inventory.movementType.adjustment\": \"Adjustment\",\n \"inventory.movementType.transfer\": \"Transfer\",\n \"inventory.movementType.loss\": \"Loss\",\n \"inventory.recipeForm.group\": \"Stage\",\n \"inventory.recipeForm.ungrouped\": \"No stage\",\n \"inventory.productList.bulkActivate\": \"Activate\",\n \"inventory.productList.bulkActivated\": \"{{count}} product(s) activated\",\n \"inventory.productList.bulkDeactivate\": \"Deactivate\",\n \"inventory.productList.bulkDeactivated\": \"{{count}} product(s) deactivated\",\n \"inventory.productList.bulkFailed\": \"{{count}} product(s) could not be updated\",\n \"inventory.productList.bulkNothingToDo\": \"The selected products are already in that state.\",\n \"inventory.productList.filterActive\": \"Active\",\n \"inventory.productList.filterAllStatuses\": \"Active and inactive\",\n \"inventory.productList.filterInactive\": \"Inactive\",\n \"inventory.productList.filterStatus\": \"Status\",\n \"inventory.productList.inactive\": \"Inactive\",\n \"inventory.productList.title\": \"Products\",\n \"inventory.productList.subtitle\": \"{{count}} products\",\n \"inventory.productList.product\": \"Product\",\n \"inventory.productList.type\": \"Type\",\n \"inventory.productList.stock\": \"Stock\",\n \"inventory.productList.cost\": \"Cost\",\n \"inventory.productList.value\": \"Value\",\n \"inventory.productList.searchPlaceholder\": \"Search products...\",\n 'inventory.productList.aiHint': 'Describe the product and I create it.',\n 'inventory.productList.askPlaceholder': 'Describe the product…',\n 'inventory.productList.askPersona': 'Product intake',\n 'inventory.productList.askPitch': 'Tell me the product you want to add.',\n 'inventory.productList.askDescription': 'Name, price, cost, SKU, kind — tell me what you know, however you say it, and I fill in the rest sensibly. You check before it saves.',\n 'inventory.productList.askSuggestion.0': 'Black tee S/M/L, $79, cost $28',\n 'inventory.productList.askSuggestion.1': 'Add 5 sample products so I can test the store',\n 'inventory.productList.askSuggestion.2': 'A bundle of the two best sellers',\n \"inventory.productList.newProduct\": \"New Product\",\n \"inventory.productList.empty\": \"No products yet\",\n \"inventory.productList.createFirst\": \"Create your first product\",\n \"inventory.stock.unknownProduct\": \"Unknown Product\",\n \"inventory.stock.reasonLossPlaceholder\": \"e.g. Expired, damaged\",\n \"inventory.stock.reasonAdjustPlaceholder\": \"e.g. Physical count correction\",\n \"inventory.stock.documentPlaceholder\": \"Invoice, receipt, PO...\",\n \"inventory.stock.batchPlaceholder\": \"e.g. LOT001\",\n \"inventory.stock.notesPlaceholder\": \"Additional notes...\",\n \"inventory.recipeDetail.loading\": \"Loading...\",\n \"inventory.recipeDetail.ingredient\": \"Ingredient\",\n \"inventory.recipeDetail.quantity\": \"Quantity\",\n \"inventory.recipeDetail.unit\": \"Unit\",\n \"inventory.recipeDetail.notes\": \"Notes\",\n \"inventory.recipeDetail.created\": \"Created\",\n \"inventory.recipeDetail.updated\": \"Updated\",\n \"inventory.recipeForm.newRecipe\": \"New Recipe\",\n \"inventory.recipeForm.subtitle\": \"Define a production formula\",\n \"inventory.recipeForm.cancel\": \"Cancel\",\n \"inventory.recipeForm.saveRecipe\": \"Save Recipe\",\n \"inventory.recipeForm.saving\": \"Saving...\",\n \"inventory.recipeForm.recipeDetails\": \"Recipe Details\",\n \"inventory.recipeForm.recipeName\": \"Recipe Name\",\n \"inventory.recipeForm.recipeNamePlaceholder\": \"e.g. Tomato Sauce\",\n \"inventory.recipeForm.description\": \"Description\",\n \"inventory.recipeForm.descriptionPlaceholder\": \"Brief description...\",\n \"inventory.recipeForm.produces\": \"Produces (Product)\",\n \"inventory.recipeForm.searchProduct\": \"Search product...\",\n \"inventory.recipeForm.createProduct\": \"Create product\",\n \"inventory.recipeForm.yieldQuantity\": \"Yield Quantity\",\n \"inventory.recipeForm.prepTime\": \"Prep Time (min)\",\n \"inventory.recipeForm.instructions\": \"Instructions\",\n \"inventory.recipeForm.instructionsPlaceholder\": \"Step-by-step preparation instructions...\",\n \"inventory.recipeForm.ingredients\": \"Ingredients\",\n \"inventory.recipeForm.addIngredient\": \"Add Ingredient\",\n \"inventory.recipeForm.noIngredients\": \"No ingredients added\",\n \"inventory.recipeForm.addFirstIngredient\": \"Add your first ingredient\",\n \"inventory.recipeForm.ingredient\": \"Ingredient\",\n \"inventory.recipeForm.quantity\": \"Quantity\",\n \"inventory.recipeForm.notes\": \"Notes\",\n \"inventory.recipeForm.searchIngredient\": \"Search ingredient...\",\n \"inventory.recipeForm.createIngredient\": \"Create ingredient\",\n \"inventory.recipeForm.notesPlaceholder\": \"e.g. diced, fresh\",\n \"inventory.recipeForm.ingredientsConfigured\": \"{{configured}} of {{total}} ingredients configured\",\n \"inventory.title\": \"Inventory\",\n \"inventory.stock.title\": \"Stock\",\n \"inventory.stock.minStock\": \"Min. Stock\",\n \"inventory.stock.adjust\": \"Adjust Stock\",\n \"inventory.stock.lowStock\": \"Low Stock\",\n \"inventory.products.title\": \"Products\",\n \"inventory.products.create\": \"New Product\",\n \"inventory.recipes.create\": \"New Recipe\",\n \"inventory.recipes.addIngredient\": \"Add Ingredient\",\n \"inventory.recipes.cost\": \"Cost\",\n \"inventory.recipes.loading\": \"Loading...\",\n \"inventory.suppliers.title\": \"Suppliers\",\n \"inventory.suppliers.create\": \"New Supplier\",\n \"inventory.movements.title\": \"Movements\",\n \"inventory.movements.in\": \"Stock In\",\n \"inventory.movements.out\": \"Stock Out\",\n \"inventory.settings.title\": \"Inventory Settings\",\n\n \"inventory.recipeDetail.cost\": \"Cost\",\n \"inventory.recipeDetail.unitCost\": \"Unit cost\",\n \"inventory.recipeDetail.totalCost\": \"Recipe cost\",\n \"inventory.recipeDetail.costPerYield\": \"Cost per unit produced\",\n \"inventory.recipeDetail.salePrice\": \"Sale price\",\n \"inventory.recipeDetail.cmv\": \"Food cost %\",\n \"inventory.recipeDetail.cmvUnknown\": \"No sale price\",\n \"inventory.recipeDetail.cmvHigh\": \"Above {{threshold}}% — this dish is eating the margin.\",\n\n \"inventory.recipeGaps.title\": \"Not linked to your catalogue\",\n \"inventory.recipeGaps.description\": \"The assistant suggested these but could not match them. Pick the equivalent item or create it.\",\n \"inventory.recipeGaps.produces\": \"Produces:\",\n \"inventory.recipeGaps.unnamed\": \"Unnamed ingredient\",\n \"inventory.recipeGaps.linkFailed\": \"Could not link this item\",\n \"inventory.recipeGaps.createFailed\": \"Could not create the product\",\n\n \"inventory.recipes.entity\": \"Recipe\",\n \"inventory.recipes.colProduct\": \"Product\",\n \"inventory.recipes.colIngredients\": \"Ingredients\",\n \"inventory.recipes.colYield\": \"Yield\",\n \"inventory.recipes.colPrep\": \"Prep\",\n \"inventory.recipes.colCost\": \"Cost\",\n \"inventory.recipes.colSale\": \"Sale\",\n \"inventory.recipes.colCmv\": \"Food cost %\",\n \"inventory.recipes.noSheet\": \"No recipe sheet\",\n \"inventory.recipes.searchPlaceholder\": \"Search menu items...\",\n \"inventory.recipes.newByHand\": \"Fill it in by hand\",\n \"inventory.recipes.newByHandHint\": \"Open the form and enter the ingredients yourself\",\n \"inventory.recipes.aiHint\": \"Describe the dish and get the sheet built with your own ingredients\",\n \"inventory.recipes.askPlaceholder\": \"e.g. recipe for smoked hump with cheese, 400g, serves 3\",\n \"inventory.recipes.askPersona\": \"Recipe sheets\",\n \"inventory.recipes.askPitch\": \"Let's cost your menu\",\n \"inventory.recipes.askDescription\": \"Describe the dish and I build the sheet from the ingredients you already have, with cost and food cost %.\",\n \"inventory.recipes.askSuggestion.0\": \"Build the recipe sheet for the smoked hump with cheese\",\n \"inventory.recipes.askSuggestion.1\": \"Which menu items still have no recipe sheet?\",\n \"inventory.recipes.askSuggestion.2\": \"Which dishes are above 35% food cost?\",\n \"inventory.recipes.loadFailed\": \"Could not load recipe sheets\",\n \"inventory.recipes.retry\": \"Try again\",\n \"inventory.recipeDetail.loadFailed\": \"Could not load this recipe sheet\",\n \"inventory.recipeDetail.retry\": \"Try again\",\n\n \"inventory.nav.counts\": \"Counts\",\n \"inventory.counts.title\": \"Stock counts\",\n \"inventory.counts.entity\": \"Stock count\",\n \"inventory.counts.colReference\": \"Count\",\n \"inventory.counts.colOpened\": \"Opened\",\n \"inventory.counts.colStatus\": \"Status\",\n \"inventory.counts.colProgress\": \"Counted\",\n \"inventory.counts.colDivergent\": \"Divergences\",\n \"inventory.counts.status.open\": \"Open\",\n \"inventory.counts.status.counting\": \"Counting\",\n \"inventory.counts.status.closed\": \"Closed\",\n \"inventory.counts.status.cancelled\": \"Cancelled\",\n \"inventory.counts.progress\": \"{{counted}} of {{total}}\",\n \"inventory.counts.newCount\": \"New count\",\n \"inventory.counts.searchPlaceholder\": \"Search counts...\",\n \"inventory.counts.empty\": \"No counts yet\",\n \"inventory.counts.formTitle\": \"Open a count\",\n \"inventory.counts.formSubtitle\": \"What the system believes is frozen the moment you open it — the variance describes the shelf, not the clock.\",\n \"inventory.counts.location\": \"Stock location\",\n \"inventory.counts.pickLocation\": \"Pick a location\",\n \"inventory.counts.category\": \"Category\",\n \"inventory.counts.allCategories\": \"Every category\",\n \"inventory.counts.reference\": \"Name\",\n \"inventory.counts.referencePlaceholder\": \"e.g. Cold room, end of August\",\n \"inventory.counts.blind\": \"Blind count\",\n \"inventory.counts.blindHint\": \"Hides the system quantity while counting, so you write what is on the shelf instead of confirming what is on the screen.\",\n \"inventory.counts.blindLine\": \"Blind — system quantity hidden\",\n \"inventory.counts.notes\": \"Notes\",\n \"inventory.counts.notesPlaceholder\": \"Anything the next person should know\",\n \"inventory.counts.open\": \"Open the count\",\n \"inventory.counts.opening\": \"Opening...\",\n \"inventory.counts.openFailed\": \"Could not open the count\",\n \"inventory.counts.cancel\": \"Cancel\",\n \"inventory.counts.notFound\": \"Count not found\",\n \"inventory.counts.noItems\": \"This count has no products\",\n \"inventory.counts.systemQty\": \"System:\",\n \"inventory.counts.notCounted\": \"Not counted\",\n \"inventory.counts.counted\": \"Counted\",\n \"inventory.counts.divergent\": \"Divergences\",\n \"inventory.counts.varianceValue\": \"Variance\",\n \"inventory.counts.saveFailed\": \"Could not save this line\",\n \"inventory.counts.close\": \"Close the count\",\n \"inventory.counts.closeTitle\": \"Close the count?\",\n \"inventory.counts.closeDescription\": \"{{divergent}} line(s) differ from the system and will get an adjustment. {{uncounted}} line(s) were never counted and are left exactly as they are.\",\n \"inventory.counts.closeConfirm\": \"Close and adjust\",\n \"inventory.counts.closed\": \"Count closed — {{count}} adjustment(s) recorded\",\n \"inventory.counts.alreadyClosed\": \"This count was already closed\",\n \"inventory.counts.closeFailed\": \"Could not close the count\",\n \"inventory.counts.cancelCount\": \"Cancel count\",\n \"inventory.counts.cancelTitle\": \"Cancel this count?\",\n \"inventory.counts.cancelDescription\": \"The count is filed away and nothing is adjusted. What you typed stays on record.\",\n \"inventory.counts.cancelConfirm\": \"Cancel the count\",\n \"inventory.counts.cancelled\": \"Count cancelled\",\n \"inventory.counts.cancelFailed\": \"Could not cancel the count\",\n \"inventory.counts.adjustmentReason\": \"Stock count {{reference}}\",\n 'inventory.productDetail.newMovement': 'Record movement',\n 'inventory.productDetail.movementFailed': 'Could not record the movement',\n \"inventory.nav.usageAudit\": \"Usage Audit\",\n \"inventory.usageAudit.title\": \"Product Usage Audit\",\n \"inventory.usageAudit.subtitle\": \"Review what the appointments consumed and correct a quantity entered wrong.\",\n \"inventory.usageAudit.columnProduct\": \"Product\",\n \"inventory.usageAudit.columnQuantity\": \"Quantity\",\n \"inventory.usageAudit.columnLocation\": \"Position\",\n \"inventory.usageAudit.columnWhen\": \"When\",\n \"inventory.usageAudit.columnPerformedBy\": \"Performed by\",\n \"inventory.usageAudit.columnCustomer\": \"Customer\",\n \"inventory.usageAudit.columnCost\": \"Cost\",\n \"inventory.usageAudit.standard\": \"Standard\",\n \"inventory.usageAudit.corrected\": \"Corrected\",\n \"inventory.usageAudit.noLocation\": \"No position\",\n \"inventory.usageAudit.unnamedProduct\": \"Unnamed product\",\n \"inventory.usageAudit.reason\": \"Audit notes\",\n \"inventory.usageAudit.cancel\": \"Cancel\",\n \"inventory.usageAudit.loadFailed\": \"Could not load the audit\",\n \"inventory.usageAudit.searchPlaceholder\": \"Search by product, customer, professional…\",\n \"inventory.usageAudit.filterLabel\": \"Review\",\n \"inventory.usageAudit.filterAll\": \"All\",\n \"inventory.usageAudit.filterDivergent\": \"Off standard\",\n \"inventory.usageAudit.empty\": \"No usage posted by appointments yet\",\n \"inventory.usageAudit.columnCounted\": \"Counted\",\n \"inventory.usageAudit.draftOne\": \"1 quantity changed\",\n \"inventory.usageAudit.draftMany\": \"{{count}} quantities changed\",\n \"inventory.usageAudit.draftCheck\": \"Check the quantities you typed\",\n \"inventory.usageAudit.draftHint\": \"Applying posts one adjustment per line, all under the same note.\",\n \"inventory.usageAudit.draftCost\": \"Consumption cost difference: {{value}}\",\n \"inventory.usageAudit.draftInvalid\": \"{{count}} line(s) hold a quantity that is not a number\",\n \"inventory.usageAudit.draftNothing\": \"No quantity has changed yet\",\n \"inventory.usageAudit.discard\": \"Discard\",\n \"inventory.usageAudit.apply\": \"Apply {{count}}\",\n \"inventory.usageAudit.applyTitle\": \"Apply {{count}} corrections\",\n \"inventory.usageAudit.applyDescription\": \"One ledger adjustment per line, all under the same note. Nothing is rewritten: the difference is posted.\",\n \"inventory.usageAudit.applyConfirm\": \"Apply\",\n \"inventory.usageAudit.batchReasonPlaceholder\": \"Why these quantities changed\\u2026\",\n \"inventory.usageAudit.batchReasonHint\": \"It covers the whole batch \\u2014 this note stays on every movement.\",\n \"inventory.usageAudit.batchApplied\": \"{{count}} corrections posted to the ledger\",\n \"inventory.usageAudit.batchFailed\": \"Could not apply the conference\",\n \"inventory.usageAudit.applyTitleOne\": \"Apply 1 correction\",\n \"inventory.usageAudit.batchReasonRequired\": \"Say why before applying — the note is required.\",\n \"inventory.usageAudit.batchAppliedOne\": \"1 correction posted to the ledger\",\n \"inventory.usageAudit.emptyDivergent\": \"No usage off the standard\",\n}\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"inventory.dashboard.activeItems\": \"Itens ativos\",\n \"inventory.dashboard.belowMinimum\": \"Abaixo do mínimo\",\n \"inventory.dashboard.entries\": \"Entradas:\",\n \"inventory.dashboard.exits\": \"Saídas:\",\n \"inventory.dashboard.last7Days\": \"Últimos 7 dias\",\n \"inventory.dashboard.lowStock\": \"Estoque Baixo\",\n \"inventory.dashboard.needRestocking\": \"Precisam reposição\",\n \"inventory.dashboard.outOfStock\": \"Sem Estoque\",\n \"inventory.dashboard.quickActions\": \"Ações Rápidas\",\n \"inventory.dashboard.quickActionsDesc\": \"Use a barra lateral para registrar entradas, saídas ou gerenciar produtos.\",\n \"inventory.dashboard.recentActivity\": \"Atividade Recente\",\n \"inventory.dashboard.stockValue\": \"Valor do Estoque\",\n \"inventory.dashboard.totalProducts\": \"Total de Produtos\",\n \"inventory.dashboard.totalValue\": \"Valor total do estoque\",\n \"inventory.history.noMovements\": \"Nenhuma movimentação registrada\",\n \"inventory.history.columnDate\": \"Data\",\n \"inventory.history.columnProduct\": \"Produto\",\n \"inventory.history.columnType\": \"Tipo\",\n \"inventory.history.columnLocation\": \"Local\",\n \"inventory.history.columnQty\": \"Qtd\",\n \"inventory.history.columnTotal\": \"Total\",\n \"inventory.history.newEntry\": \"Nova entrada\",\n \"inventory.history.newExit\": \"Saída\",\n \"inventory.nav.recipes\": \"Receitas\",\n \"registry.suppliers\": \"Fornecedores\",\n \"registry.suppliers.description\": \"De quem você compra\",\n \"registry.product-categories\": \"Categorias\",\n \"registry.product-categories.description\": \"Como o catálogo é agrupado\",\n \"registry.stock-locations\": \"Locais de estoque\",\n \"registry.stock-locations.description\": \"Onde o estoque fica de fato — câmara fria, estoque seco, freezer\",\n \"registry.measurement-units\": \"Unidades de medida\",\n \"registry.measurement-units.description\": \"Como cada item é contado\",\n \"inventory.history.searchPlaceholder\": \"Buscar movimentações...\",\n \"inventory.history.subtitle\": \"Todas as movimentações de estoque\",\n \"inventory.history.title\": \"Histórico de Estoque\",\n \"inventory.nav.dashboard\": \"Painel\",\n \"inventory.nav.entry\": \"Entrada\",\n \"inventory.nav.exit\": \"Saída\",\n \"inventory.nav.history\": \"Histórico\",\n \"inventory.nav.list\": \"Lista\",\n \"inventory.nav.new\": \"Novo\",\n \"inventory.nav.products\": \"Produtos\",\n \"inventory.nav.stock\": \"Estoque\",\n \"inventory.page.newProduct\": \"Novo Produto\",\n \"inventory.page.newProductDesc\": \"Adicionar um produto ao seu catálogo\",\n \"inventory.page.settingsSubtitle\": \"Preferências, fornecedores, categorias e unidades\",\n \"inventory.page.settingsTitle\": \"Configurações de Estoque\",\n \"inventory.page.stockEntry\": \"Entrada de Estoque\",\n \"inventory.page.stockEntryDesc\": \"Registrar mercadorias recebidas\",\n \"inventory.page.stockExit\": \"Saída de Estoque\",\n \"inventory.page.stockExitDesc\": \"Registrar mercadorias usadas ou vendidas\",\n \"inventory.recipeDetail.active\": \"Ativa\",\n \"inventory.recipeDetail.backToList\": \"Voltar à lista\",\n \"inventory.recipeDetail.inactive\": \"Inativa\",\n \"inventory.recipeDetail.ingredientCount\": \"Ingredientes\",\n \"inventory.recipeDetail.ingredientsTitle\": \"Ingredientes\",\n \"inventory.recipeDetail.instructions\": \"Instruções\",\n \"inventory.recipeDetail.noIngredients\": \"Nenhum ingrediente definido\",\n \"inventory.recipeDetail.notFound\": \"Receita não encontrada\",\n \"inventory.recipeDetail.prepTime\": \"Tempo de preparo\",\n \"inventory.recipeDetail.produces\": \"Produz\",\n \"inventory.recipeDetail.recipes\": \"Receitas\",\n \"inventory.recipeDetail.yield\": \"Rendimento\",\n \"inventory.recipes.createFirst\": \"Crie sua primeira receita\",\n \"inventory.recipes.ingredients\": \"Ingredientes\",\n \"inventory.recipes.newRecipe\": \"Nova Receita\",\n \"inventory.recipes.noRecipes\": \"Nenhuma receita ainda\",\n \"inventory.recipes.produces\": \"Produz:\",\n \"inventory.recipes.productionFormulas\": \"{{count}} fórmulas de produção\",\n \"inventory.recipes.recipesDesc\": \"Receitas definem como produzir produtos a partir de ingredientes\",\n \"inventory.recipes.title\": \"Receitas\",\n \"inventory.recipes.yield\": \"Rendimento\",\n \"inventory.stock.additionalDetails\": \"Detalhes adicionais (opcional)\",\n \"inventory.stock.adjustmentDesc\": \"Correção de contagem\",\n \"inventory.stock.adjustmentLabel\": \"Ajuste\",\n \"inventory.stock.back\": \"Voltar\",\n \"inventory.stock.batchNumber\": \"Número do Lote\",\n \"inventory.stock.currentStock\": \"Estoque Atual\",\n \"inventory.stock.destination\": \"Destino\",\n \"inventory.stock.document\": \"Documento\",\n \"inventory.stock.documentNumber\": \"Número do Documento\",\n \"inventory.stock.entry\": \"Entrada de Estoque\",\n \"inventory.stock.entryDesc\": \"Recebimento de mercadorias\",\n \"inventory.stock.entryLabel\": \"Entrada\",\n \"inventory.stock.exit\": \"Saída de Estoque\",\n \"inventory.stock.exitDesc\": \"Uso ou venda\",\n \"inventory.stock.exitLabel\": \"Saída\",\n \"inventory.stock.expirationDate\": \"Data de Validade\",\n \"inventory.stock.fromLocation\": \"Local de Origem\",\n \"inventory.stock.locationLabel\": \"Local\",\n \"inventory.stock.lossDesc\": \"Desperdício ou dano\",\n \"inventory.stock.lossLabel\": \"Perda\",\n \"inventory.stock.movement\": \"Movimentação de Estoque\",\n \"inventory.stock.movementDetails\": \"Detalhes da Movimentação\",\n \"inventory.stock.movementType\": \"Tipo de movimentação\",\n \"inventory.stock.next\": \"Próximo\",\n \"inventory.stock.notes\": \"Observações\",\n \"inventory.stock.product\": \"Produto\",\n \"inventory.stock.quantity\": \"Quantidade *\",\n \"inventory.stock.quantityLabel\": \"Quantidade\",\n \"inventory.stock.reason\": \"Motivo *\",\n \"inventory.stock.reasonLabel\": \"Motivo\",\n \"inventory.stock.recordMovement\": \"Registrar Movimentação\",\n \"inventory.stock.recorded\": \"Registrado\",\n \"inventory.stock.recording\": \"Registrando...\",\n \"inventory.stock.searchProduct\": \"Buscar por nome, SKU ou código de barras...\",\n \"inventory.stock.stepOf\": \"Etapa {{step}} de 3\",\n \"inventory.stock.supplier\": \"Fornecedor\",\n \"inventory.stock.toLocation\": \"Local de Destino *\",\n \"inventory.stock.total\": \"Total\",\n \"inventory.stock.totalCost\": \"Custo Total\",\n \"inventory.stock.transferDesc\": \"Entre locais\",\n \"inventory.stock.transferLabel\": \"Transferência\",\n \"inventory.stock.unitCost\": \"Custo Unitário\",\n \"inventory.stock.unitCostLabel\": \"Custo Unitário\",\n \"inventory.stock.searchSupplier\": \"Buscar fornecedor...\",\n \"inventory.stock.noSuppliers\": \"Nenhum fornecedor cadastrado\",\n \"inventory.productDetail.stockTab\": \"Estoque\",\n \"inventory.productDetail.positionsTitle\": \"Estoque por local\",\n \"inventory.productDetail.onHand\": \"Em estoque\",\n \"inventory.productDetail.noPositions\": \"Sem estoque em nenhum local\",\n \"inventory.productDetail.historyTitle\": \"Movimentação\",\n \"inventory.productDetail.undoLast\": \"Desfazer último movimento\",\n \"inventory.productDetail.undoTitle\": \"Desfazer o último movimento?\",\n \"inventory.productDetail.undoDescription\": \"{{type}} de {{quantity}} em {{date}} sai do histórico, e o estoque que ele moveu volta.\",\n \"inventory.productDetail.undoConfirm\": \"Desfazer\",\n \"inventory.productDetail.undone\": \"Movimento desfeito\",\n \"inventory.productDetail.undoFailed\": \"Não foi possível desfazer o movimento\",\n \"inventory.productDetail.notFound\": \"Produto não encontrado\",\n \"inventory.productDetail.backToList\": \"Voltar para produtos\",\n \"inventory.onboarding.welcome\": \"Bem-vindo ao Estoque\",\n \"inventory.onboarding.description\": \"Acompanhe produtos, gerencie níveis de estoque e monitore movimentações do seu negócio.\",\n \"inventory.onboarding.skip\": \"Pular configuração\",\n \"inventory.onboarding.getStarted\": \"Começar\",\n \"inventory.onboarding.units.title\": \"Unidades de Medida\",\n \"inventory.onboarding.units.description\": \"Unidades padrão (Unidade, Caixa, Kg, L, etc.) estão prontas. Personalize-as a qualquer momento em Configurações.\",\n \"inventory.onboarding.locations.title\": \"Locais de Estoque\",\n \"inventory.onboarding.locations.description\": \"Um local de armazenamento padrão foi criado. Adicione mais para controle multi-local.\",\n \"inventory.onboarding.start\": \"Começar a usar Estoque\",\n \"inventory.onboarding.preparing\": \"Preparando estoque...\",\n \"inventory.onboarding.setupError\": \"Não foi possível preparar as unidades e o local padrão. Tente novamente.\",\n \"inventory.quickActions.newProduct\": \"Novo Produto\",\n \"inventory.quickActions.newProductDesc\": \"Adicionar um produto ao catálogo\",\n \"inventory.quickActions.stockEntry\": \"Entrada de Estoque\",\n \"inventory.quickActions.stockEntryDesc\": \"Registrar mercadorias recebidas\",\n \"inventory.quickActions.stockExit\": \"Saída de Estoque\",\n \"inventory.quickActions.stockExitDesc\": \"Registrar mercadorias usadas ou vendidas\",\n \"inventory.settingsPage.title\": \"Configurações de Estoque\",\n \"inventory.settingsPage.subtitle\": \"Gerenciar unidades, categorias e locais de estoque\",\n \"inventory.settings.stockManagement\": \"Gestão de Estoque\",\n \"inventory.settings.stockManagementDesc\": \"Como os níveis de estoque são rastreados\",\n \"inventory.settings.lowStockAlerts\": \"Alertas de estoque baixo\",\n \"inventory.settings.lowStockAlertsDesc\": \"Mostrar avisos quando produtos ficarem abaixo da quantidade mínima\",\n \"inventory.settings.requireReason\": \"Exigir motivo para ajustes\",\n \"inventory.settings.requireReasonDesc\": \"Tornar obrigatório o motivo para ajustes e perdas de estoque\",\n \"inventory.settings.autoDeduct\": \"Auto-deduzir no serviço\",\n \"inventory.settings.autoDeductDesc\": \"Deduzir automaticamente produtos quando um serviço é executado\",\n \"inventory.settings.products\": \"Produtos\",\n \"inventory.settings.productsDesc\": \"Comportamento do catálogo de produtos\",\n \"inventory.settings.requireSku\": \"Exigir SKU\",\n \"inventory.settings.requireSkuDesc\": \"Tornar SKU obrigatório ao criar produtos\",\n \"inventory.settings.allowNegative\": \"Permitir estoque negativo\",\n \"inventory.settings.allowNegativeDesc\": \"Permitir que quantidades de estoque fiquem abaixo de zero\",\n \"inventory.settings.notifications\": \"Notificações\",\n \"inventory.settings.notificationsDesc\": \"Alertas e lembretes\",\n \"inventory.settings.lowStockEmail\": \"Alertas de estoque baixo por e-mail\",\n \"inventory.settings.lowStockEmailDesc\": \"Enviar e-mail quando produtos atingirem a quantidade mínima\",\n \"inventory.settings.expiryWarnings\": \"Avisos de validade\",\n \"inventory.settings.expiryWarningsDesc\": \"Alertar antes de produtos vencerem (rastreamento de lotes)\",\n \"inventory.productForm.newProduct\": \"Novo Produto\",\n \"inventory.productForm.editProduct\": \"Editar Produto\",\n \"inventory.productForm.updateDetails\": \"Atualizar detalhes do produto\",\n \"inventory.productForm.addToCatalog\": \"Adicionar um produto ao seu catálogo\",\n \"inventory.productForm.cancel\": \"Cancelar\",\n \"inventory.productForm.save\": \"Salvar\",\n \"inventory.productForm.saving\": \"Salvando...\",\n \"inventory.productForm.generalInfo\": \"Informações Gerais\",\n \"inventory.productForm.name\": \"Nome\",\n \"inventory.productForm.namePlaceholder\": \"Nome do produto\",\n \"inventory.productForm.brand\": \"Marca\",\n \"inventory.productForm.brandPlaceholder\": \"Nome da marca\",\n \"inventory.productForm.sku\": \"SKU\",\n \"inventory.productForm.skuPlaceholder\": \"Código interno\",\n \"inventory.productForm.barcode\": \"Código de Barras\",\n \"inventory.productForm.barcodePlaceholder\": \"EAN / UPC\",\n \"inventory.productForm.description\": \"Descrição\",\n \"inventory.productForm.descriptionPlaceholder\": \"Informações adicionais sobre o produto\",\n \"inventory.productForm.classification\": \"Classificação\",\n \"inventory.productForm.classificationDesc\": \"Como este produto é usado no seu negócio\",\n \"inventory.productForm.typeIngredient\": \"Matéria-prima usada na produção ou serviços\",\n \"inventory.productForm.typeSale\": \"Vendido diretamente aos clientes\",\n \"inventory.productForm.typeIntermediate\": \"Produzido internamente a partir de outros itens\",\n \"inventory.productForm.typeAsset\": \"Ativo fixo para controle patrimonial\",\n \"inventory.productForm.pricing\": \"Preços\",\n \"inventory.productForm.costPrice\": \"Preço de Custo\",\n \"inventory.productForm.salePrice\": \"Preço de Venda\",\n \"inventory.productForm.margin\": \"Margem\",\n \"inventory.productForm.stockLevels\": \"Níveis de Estoque\",\n \"inventory.productForm.stockLevelsDesc\": \"Limites mínimo e máximo para alertas\",\n \"inventory.productForm.minQuantity\": \"Quantidade Mínima\",\n \"inventory.productForm.minQuantityHint\": \"Alertar quando o estoque ficar abaixo deste valor\",\n \"inventory.productForm.maxQuantity\": \"Quantidade Máxima\",\n \"inventory.productForm.maxQuantityHint\": \"Capacidade máxima para este produto\",\n \"inventory.productForm.optional\": \"Opcional\",\n \"inventory.productForm.organization\": \"Organização\",\n \"inventory.productForm.organizationDesc\": \"Categoria, unidade, fornecedor e local padrão de estoque\",\n \"inventory.productForm.category\": \"Categoria\",\n \"inventory.productForm.measurementUnit\": \"Unidade de medida\",\n \"inventory.productForm.measurementUnitHint\": \"Como este item é contado no estoque\",\n \"inventory.productForm.supplier\": \"Fornecedor padrão\",\n \"inventory.productForm.defaultLocation\": \"Local padrão\",\n \"inventory.movementType.entry\": \"Entrada\",\n \"inventory.movementType.exit\": \"Saída\",\n \"inventory.movementType.adjustment\": \"Ajuste\",\n \"inventory.movementType.transfer\": \"Transferência\",\n \"inventory.movementType.loss\": \"Perda\",\n \"inventory.recipeForm.group\": \"Etapa\",\n \"inventory.recipeForm.ungrouped\": \"Sem etapa\",\n \"inventory.productList.bulkActivate\": \"Ativar\",\n \"inventory.productList.bulkActivated\": \"{{count}} produto(s) ativado(s)\",\n \"inventory.productList.bulkDeactivate\": \"Desativar\",\n \"inventory.productList.bulkDeactivated\": \"{{count}} produto(s) desativado(s)\",\n \"inventory.productList.bulkFailed\": \"{{count}} produto(s) não puderam ser atualizados\",\n \"inventory.productList.bulkNothingToDo\": \"Os produtos selecionados já estão nesse estado.\",\n \"inventory.productList.filterActive\": \"Ativos\",\n \"inventory.productList.filterAllStatuses\": \"Ativos e inativos\",\n \"inventory.productList.filterInactive\": \"Inativos\",\n \"inventory.productList.filterStatus\": \"Situação\",\n \"inventory.productList.inactive\": \"Inativo\",\n \"inventory.productList.title\": \"Produtos\",\n \"inventory.productList.subtitle\": \"{{count}} produtos\",\n \"inventory.productList.product\": \"Produto\",\n \"inventory.productList.type\": \"Tipo\",\n \"inventory.productList.stock\": \"Estoque\",\n \"inventory.productList.cost\": \"Custo\",\n \"inventory.productList.value\": \"Valor\",\n \"inventory.productList.searchPlaceholder\": \"Buscar produtos...\",\n 'inventory.productList.aiHint': 'Descreva o produto e eu cadastro.',\n 'inventory.productList.askPlaceholder': 'Descreva o produto…',\n 'inventory.productList.askPersona': 'Cadastro de produtos',\n 'inventory.productList.askPitch': 'Diga o produto que você quer cadastrar.',\n 'inventory.productList.askDescription': 'Nome, preço, custo, SKU, tipo — diga o que souber, do jeito que falar, e eu preencho o resto com o que faz sentido. Você confere antes de salvar.',\n 'inventory.productList.askSuggestion.0': 'Camiseta preta P/M/G, R$ 79, custo R$ 28',\n 'inventory.productList.askSuggestion.1': 'Cadastre 5 produtos de exemplo para eu testar a loja',\n 'inventory.productList.askSuggestion.2': 'Um combo com os dois itens mais vendidos',\n \"inventory.productList.newProduct\": \"Novo Produto\",\n \"inventory.productList.empty\": \"Nenhum produto ainda\",\n \"inventory.productList.createFirst\": \"Crie seu primeiro produto\",\n \"inventory.stock.unknownProduct\": \"Produto Desconhecido\",\n \"inventory.stock.reasonLossPlaceholder\": \"ex. Vencido, danificado\",\n \"inventory.stock.reasonAdjustPlaceholder\": \"ex. Correção de contagem física\",\n \"inventory.stock.documentPlaceholder\": \"Nota fiscal, recibo, PO...\",\n \"inventory.stock.batchPlaceholder\": \"ex. LOT001\",\n \"inventory.stock.notesPlaceholder\": \"Observações adicionais...\",\n \"inventory.recipeDetail.loading\": \"Carregando...\",\n \"inventory.recipeDetail.ingredient\": \"Ingrediente\",\n \"inventory.recipeDetail.quantity\": \"Quantidade\",\n \"inventory.recipeDetail.unit\": \"Unidade\",\n \"inventory.recipeDetail.notes\": \"Observações\",\n \"inventory.recipeDetail.created\": \"Criado\",\n \"inventory.recipeDetail.updated\": \"Atualizado\",\n \"inventory.recipeForm.newRecipe\": \"Nova Receita\",\n \"inventory.recipeForm.subtitle\": \"Definir uma fórmula de produção\",\n \"inventory.recipeForm.cancel\": \"Cancelar\",\n \"inventory.recipeForm.saveRecipe\": \"Salvar Receita\",\n \"inventory.recipeForm.saving\": \"Salvando...\",\n \"inventory.recipeForm.recipeDetails\": \"Detalhes da Receita\",\n \"inventory.recipeForm.recipeName\": \"Nome da Receita\",\n \"inventory.recipeForm.recipeNamePlaceholder\": \"ex. Molho de Tomate\",\n \"inventory.recipeForm.description\": \"Descrição\",\n \"inventory.recipeForm.descriptionPlaceholder\": \"Breve descrição...\",\n \"inventory.recipeForm.produces\": \"Produz (Produto)\",\n \"inventory.recipeForm.searchProduct\": \"Buscar produto...\",\n \"inventory.recipeForm.createProduct\": \"Criar produto\",\n \"inventory.recipeForm.yieldQuantity\": \"Quantidade de Rendimento\",\n \"inventory.recipeForm.prepTime\": \"Tempo de Preparo (min)\",\n \"inventory.recipeForm.instructions\": \"Instruções\",\n \"inventory.recipeForm.instructionsPlaceholder\": \"Instruções de preparo passo a passo...\",\n \"inventory.recipeForm.ingredients\": \"Ingredientes\",\n \"inventory.recipeForm.addIngredient\": \"Adicionar Ingrediente\",\n \"inventory.recipeForm.noIngredients\": \"Nenhum ingrediente adicionado\",\n \"inventory.recipeForm.addFirstIngredient\": \"Adicione seu primeiro ingrediente\",\n \"inventory.recipeForm.ingredient\": \"Ingrediente\",\n \"inventory.recipeForm.quantity\": \"Quantidade\",\n \"inventory.recipeForm.notes\": \"Observações\",\n \"inventory.recipeForm.searchIngredient\": \"Buscar ingrediente...\",\n \"inventory.recipeForm.createIngredient\": \"Criar ingrediente\",\n \"inventory.recipeForm.notesPlaceholder\": \"ex. picado, fresco\",\n \"inventory.recipeForm.ingredientsConfigured\": \"{{configured}} de {{total}} ingredientes configurados\",\n \"inventory.title\": \"Estoque\",\n \"inventory.stock.title\": \"Estoque\",\n \"inventory.stock.minStock\": \"Estoque Mín.\",\n \"inventory.stock.adjust\": \"Ajustar Estoque\",\n \"inventory.stock.lowStock\": \"Estoque Baixo\",\n \"inventory.products.title\": \"Produtos\",\n \"inventory.products.create\": \"Novo Produto\",\n \"inventory.recipes.create\": \"Nova Receita\",\n \"inventory.recipes.addIngredient\": \"Adicionar Ingrediente\",\n \"inventory.recipes.cost\": \"Custo\",\n \"inventory.recipes.loading\": \"Carregando...\",\n \"inventory.suppliers.title\": \"Fornecedores\",\n \"inventory.suppliers.create\": \"Novo Fornecedor\",\n \"inventory.movements.title\": \"Movimentações\",\n \"inventory.movements.in\": \"Entrada\",\n \"inventory.movements.out\": \"Saída\",\n \"inventory.settings.title\": \"Configurações de Estoque\",\n\n \"inventory.recipeDetail.cost\": \"Custo\",\n \"inventory.recipeDetail.unitCost\": \"Custo unitário\",\n \"inventory.recipeDetail.totalCost\": \"Custo da ficha\",\n \"inventory.recipeDetail.costPerYield\": \"Custo por unidade produzida\",\n \"inventory.recipeDetail.salePrice\": \"Preço de venda\",\n \"inventory.recipeDetail.cmv\": \"CMV\",\n \"inventory.recipeDetail.cmvUnknown\": \"Sem preço de venda\",\n \"inventory.recipeDetail.cmvHigh\": \"Acima de {{threshold}}% — este prato está comendo a margem.\",\n\n \"inventory.recipeGaps.title\": \"Falta ligar ao seu catálogo\",\n \"inventory.recipeGaps.description\": \"A assistente sugeriu estes itens mas não achou equivalente. Escolha o insumo certo ou cadastre.\",\n \"inventory.recipeGaps.produces\": \"Produz:\",\n \"inventory.recipeGaps.unnamed\": \"Ingrediente sem nome\",\n \"inventory.recipeGaps.linkFailed\": \"Não foi possível ligar este item\",\n \"inventory.recipeGaps.createFailed\": \"Não foi possível cadastrar o produto\",\n\n \"inventory.recipes.entity\": \"Ficha técnica\",\n \"inventory.recipes.colProduct\": \"Produto\",\n \"inventory.recipes.colIngredients\": \"Insumos\",\n \"inventory.recipes.colYield\": \"Rendimento\",\n \"inventory.recipes.colPrep\": \"Preparo\",\n \"inventory.recipes.colCost\": \"Custo\",\n \"inventory.recipes.colSale\": \"Venda\",\n \"inventory.recipes.colCmv\": \"CMV\",\n \"inventory.recipes.noSheet\": \"Sem ficha técnica\",\n \"inventory.recipes.searchPlaceholder\": \"Buscar item do cardápio...\",\n \"inventory.recipes.newByHand\": \"Preencher à mão\",\n \"inventory.recipes.newByHandHint\": \"Abrir o formulário e lançar os insumos você mesmo\",\n \"inventory.recipes.aiHint\": \"Descreva o prato e receba a ficha montada com os seus insumos\",\n \"inventory.recipes.askPlaceholder\": \"ex. ficha técnica do cupim defumado com queijo, 400g, serve 3\",\n \"inventory.recipes.askPersona\": \"Fichas técnicas\",\n \"inventory.recipes.askPitch\": \"Vamos custear o seu cardápio\",\n \"inventory.recipes.askDescription\": \"Descreva o prato que eu monto a ficha com os insumos que você já tem, com custo e CMV.\",\n \"inventory.recipes.askSuggestion.0\": \"Monte a ficha técnica do cupim defumado com queijo\",\n \"inventory.recipes.askSuggestion.1\": \"Quais itens do cardápio ainda não têm ficha técnica?\",\n \"inventory.recipes.askSuggestion.2\": \"Quais pratos estão acima de 35% de CMV?\",\n \"inventory.recipes.loadFailed\": \"Não foi possível carregar as fichas técnicas\",\n \"inventory.recipes.retry\": \"Tentar novamente\",\n \"inventory.recipeDetail.loadFailed\": \"Não foi possível carregar esta ficha técnica\",\n \"inventory.recipeDetail.retry\": \"Tentar novamente\",\n\n \"inventory.nav.counts\": \"Contagens\",\n \"inventory.counts.title\": \"Contagens de estoque\",\n \"inventory.counts.entity\": \"Contagem\",\n \"inventory.counts.colReference\": \"Contagem\",\n \"inventory.counts.colOpened\": \"Aberta em\",\n \"inventory.counts.colStatus\": \"Situação\",\n \"inventory.counts.colProgress\": \"Contados\",\n \"inventory.counts.colDivergent\": \"Divergências\",\n \"inventory.counts.status.open\": \"Aberta\",\n \"inventory.counts.status.counting\": \"Contando\",\n \"inventory.counts.status.closed\": \"Fechada\",\n \"inventory.counts.status.cancelled\": \"Cancelada\",\n \"inventory.counts.progress\": \"{{counted}} de {{total}}\",\n \"inventory.counts.newCount\": \"Nova contagem\",\n \"inventory.counts.searchPlaceholder\": \"Buscar contagem...\",\n \"inventory.counts.empty\": \"Nenhuma contagem ainda\",\n \"inventory.counts.formTitle\": \"Abrir uma contagem\",\n \"inventory.counts.formSubtitle\": \"O que o sistema acredita é congelado na hora em que você abre — a variação fala da prateleira, não do relógio.\",\n \"inventory.counts.location\": \"Local de estoque\",\n \"inventory.counts.pickLocation\": \"Escolha um local\",\n \"inventory.counts.category\": \"Categoria\",\n \"inventory.counts.allCategories\": \"Todas as categorias\",\n \"inventory.counts.reference\": \"Nome\",\n \"inventory.counts.referencePlaceholder\": \"ex. Câmara fria, fim de agosto\",\n \"inventory.counts.blind\": \"Contagem cega\",\n \"inventory.counts.blindHint\": \"Esconde a quantidade do sistema enquanto você conta, para escrever o que está na prateleira em vez de confirmar o que está na tela.\",\n \"inventory.counts.blindLine\": \"Cega — quantidade do sistema oculta\",\n \"inventory.counts.notes\": \"Observações\",\n \"inventory.counts.notesPlaceholder\": \"O que a próxima pessoa precisa saber\",\n \"inventory.counts.open\": \"Abrir a contagem\",\n \"inventory.counts.opening\": \"Abrindo...\",\n \"inventory.counts.openFailed\": \"Não foi possível abrir a contagem\",\n \"inventory.counts.cancel\": \"Cancelar\",\n \"inventory.counts.notFound\": \"Contagem não encontrada\",\n \"inventory.counts.noItems\": \"Esta contagem não tem produtos\",\n \"inventory.counts.systemQty\": \"Sistema:\",\n \"inventory.counts.notCounted\": \"Não contado\",\n \"inventory.counts.counted\": \"Contados\",\n \"inventory.counts.divergent\": \"Divergências\",\n \"inventory.counts.varianceValue\": \"Variação\",\n \"inventory.counts.saveFailed\": \"Não foi possível salvar esta linha\",\n \"inventory.counts.close\": \"Fechar a contagem\",\n \"inventory.counts.closeTitle\": \"Fechar a contagem?\",\n \"inventory.counts.closeDescription\": \"{{divergent}} linha(s) divergem do sistema e vão receber um ajuste. {{uncounted}} linha(s) ninguém contou e ficam exatamente como estão.\",\n \"inventory.counts.closeConfirm\": \"Fechar e ajustar\",\n \"inventory.counts.closed\": \"Contagem fechada — {{count}} ajuste(s) lançado(s)\",\n \"inventory.counts.alreadyClosed\": \"Esta contagem já estava fechada\",\n \"inventory.counts.closeFailed\": \"Não foi possível fechar a contagem\",\n \"inventory.counts.cancelCount\": \"Cancelar contagem\",\n \"inventory.counts.cancelTitle\": \"Cancelar esta contagem?\",\n \"inventory.counts.cancelDescription\": \"A contagem é arquivada e nada é ajustado. O que você digitou fica registrado.\",\n \"inventory.counts.cancelConfirm\": \"Cancelar a contagem\",\n \"inventory.counts.cancelled\": \"Contagem cancelada\",\n \"inventory.counts.cancelFailed\": \"Não foi possível cancelar a contagem\",\n \"inventory.counts.adjustmentReason\": \"Contagem de estoque {{reference}}\",\n 'inventory.productDetail.newMovement': 'Lançar movimento',\n 'inventory.productDetail.movementFailed': 'Não foi possível lançar o movimento',\n \"inventory.nav.usageAudit\": \"Auditoria de Uso\",\n \"inventory.usageAudit.title\": \"Auditoria de Uso de Produtos\",\n \"inventory.usageAudit.subtitle\": \"Confira o que os atendimentos consumiram e corrija a quantidade lançada errada.\",\n \"inventory.usageAudit.columnProduct\": \"Produto\",\n \"inventory.usageAudit.columnQuantity\": \"Quantidade\",\n \"inventory.usageAudit.columnLocation\": \"Posição\",\n \"inventory.usageAudit.columnWhen\": \"Quando\",\n \"inventory.usageAudit.columnPerformedBy\": \"Profissional\",\n \"inventory.usageAudit.columnCustomer\": \"Cliente\",\n \"inventory.usageAudit.columnCost\": \"Custo\",\n \"inventory.usageAudit.standard\": \"Padrão\",\n \"inventory.usageAudit.corrected\": \"Corrigido\",\n \"inventory.usageAudit.noLocation\": \"Sem posição\",\n \"inventory.usageAudit.unnamedProduct\": \"Produto sem nome\",\n \"inventory.usageAudit.reason\": \"Observações da auditoria\",\n \"inventory.usageAudit.cancel\": \"Cancelar\",\n \"inventory.usageAudit.loadFailed\": \"Não foi possível carregar a auditoria\",\n \"inventory.usageAudit.searchPlaceholder\": \"Buscar por produto, cliente, profissional…\",\n \"inventory.usageAudit.filterLabel\": \"Conferência\",\n \"inventory.usageAudit.filterAll\": \"Tudo\",\n \"inventory.usageAudit.filterDivergent\": \"Fora do padrão\",\n \"inventory.usageAudit.empty\": \"Nenhum consumo lançado pelos atendimentos ainda\",\n \"inventory.usageAudit.columnCounted\": \"Conferido\",\n \"inventory.usageAudit.draftOne\": \"1 quantidade alterada\",\n \"inventory.usageAudit.draftMany\": \"{{count}} quantidades alteradas\",\n \"inventory.usageAudit.draftCheck\": \"Confira as quantidades digitadas\",\n \"inventory.usageAudit.draftHint\": \"Aplicar lan\\u00e7a um ajuste por linha, todos com a mesma observa\\u00e7\\u00e3o.\",\n \"inventory.usageAudit.draftCost\": \"Diferen\\u00e7a de custo do consumo: {{value}}\",\n \"inventory.usageAudit.draftInvalid\": \"{{count}} linha(s) com quantidade que n\\u00e3o \\u00e9 um n\\u00famero\",\n \"inventory.usageAudit.draftNothing\": \"Nenhuma quantidade mudou ainda\",\n \"inventory.usageAudit.discard\": \"Descartar\",\n \"inventory.usageAudit.apply\": \"Aplicar {{count}}\",\n \"inventory.usageAudit.applyTitle\": \"Aplicar {{count}} correções\",\n \"inventory.usageAudit.applyDescription\": \"Um ajuste por linha no raz\\u00e3o, todos com a mesma observa\\u00e7\\u00e3o. Nada \\u00e9 reescrito: a diferen\\u00e7a \\u00e9 lan\\u00e7ada.\",\n \"inventory.usageAudit.applyConfirm\": \"Aplicar\",\n \"inventory.usageAudit.batchReasonPlaceholder\": \"Por que estas quantidades mudaram\\u2026\",\n \"inventory.usageAudit.batchReasonHint\": \"Vale para o lote inteiro \\u2014 \\u00e9 a observa\\u00e7\\u00e3o que ficar\\u00e1 em cada movimento.\",\n \"inventory.usageAudit.batchApplied\": \"{{count}} correções lançadas no razão\",\n \"inventory.usageAudit.batchFailed\": \"N\\u00e3o foi poss\\u00edvel aplicar a confer\\u00eancia\",\n \"inventory.usageAudit.applyTitleOne\": \"Aplicar 1 correção\",\n \"inventory.usageAudit.batchReasonRequired\": \"Escreva por que, antes de aplicar — a observação é obrigatória.\",\n \"inventory.usageAudit.batchAppliedOne\": \"1 correção lançada no razão\",\n \"inventory.usageAudit.emptyDivergent\": \"Nenhum consumo fora do padrão\",\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const inventoryLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_the_usage_that_left_stock_can_be_audited.sql, 002_a_auditoria_fecha_em_lote.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 = `-- ============================================================================\n-- plugins/plugin-inventory/src/migrations/000_baseline.sql — what installing this provisions, as one file.\n--\n-- GENERATED by scripts/emit-unit-baselines.mjs (#338). Do not edit by hand:\n-- change the schema, regenerate, and let scripts/check-chain-equivalence.mjs\n-- prove the result still matches.\n--\n-- This replaced 28 migration files. They are kept, unapplied, in\n-- migrations.archive/ — a year of decisions is worth reading even when it is no\n-- longer worth replaying.\n--\n-- Object order is fixed rather than dependency-sorted: schemas, types,\n-- sequences, tables, defaults, functions, constraints, views, indexes, foreign\n-- keys, triggers, row security, policies, grants. Dependencies BETWEEN units\n-- are carried by the order packages/db/chain.json declares.\n-- ============================================================================\n\n-- A LANGUAGE sql function binds its body at CREATE time, and 570 functions\n-- sorted by name are not sorted by who calls whom. This is what lets them load\n-- in any order; every body is still compiled on first call, so a genuinely\n-- broken reference surfaces then rather than never. Session-scoped.\nSET check_function_bodies = false;\n\n\n\n-- ── default privileges: reset ───────────────────────────────────────────\n-- Cleared BEFORE anything is created, so every object below gets the ACL the\n-- dump describes rather than the image's defaults on top of it. Restored at\n-- the end of this file.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON SEQUENCES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL ON TABLES FROM anon, authenticated, service_role, fayz_connector$stmt$;\nEND $dp$;\n\n\n-- ── table ───────────────────────────────────────────────────────────────\n\nCREATE TABLE public.plg_inventory_count_items (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n session_id uuid NOT NULL,\n product_id uuid NOT NULL,\n system_quantity numeric(14,4) DEFAULT 0 NOT NULL,\n counted_quantity numeric(14,4),\n unit_cost numeric(14,2) DEFAULT 0 NOT NULL,\n notes text,\n counted_at timestamp with time zone,\n counted_by uuid,\n movement_id uuid,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid,\n owner_id uuid\n);\n\nALTER TABLE ONLY public.plg_inventory_count_items FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_count_sessions (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n reference text,\n status text DEFAULT 'open'::text NOT NULL,\n stock_location_id uuid NOT NULL,\n category_id uuid,\n blind boolean DEFAULT true NOT NULL,\n notes text,\n opened_at timestamp with time zone DEFAULT now() NOT NULL,\n opened_by uuid,\n closed_at timestamp with time zone,\n closed_by uuid,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid,\n owner_id uuid,\n CONSTRAINT plg_inventory_count_sessions_status_check CHECK ((status = ANY (ARRAY['open'::text, 'counting'::text, 'closed'::text, 'cancelled'::text])))\n);\n\nALTER TABLE ONLY public.plg_inventory_count_sessions FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_fulfillment_items (\n item_id uuid NOT NULL,\n parent_kind text DEFAULT 'fulfillment'::text NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n batch_number text,\n expiration_date date,\n delivered_by uuid,\n stock_location_id uuid,\n movement_id uuid,\n owner_id uuid,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n CONSTRAINT plg_inventory_fulfillment_items_parent_kind_check CHECK ((parent_kind = 'fulfillment'::text))\n);\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_measurement_units (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n abbreviation text NOT NULL,\n is_active boolean DEFAULT true 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 unit_id uuid,\n owner_id uuid,\n code text,\n kind text DEFAULT 'unit'::text NOT NULL,\n is_base boolean DEFAULT false NOT NULL,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n CONSTRAINT plg_inventory_measurement_units_kind_check CHECK ((kind = ANY (ARRAY['unit'::text, 'mass'::text, 'volume'::text, 'length'::text])))\n);\n\nALTER TABLE ONLY public.plg_inventory_measurement_units FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_operations (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n kind text NOT NULL,\n idempotency_key text NOT NULL,\n status text DEFAULT 'pending'::text NOT NULL,\n actor_id uuid,\n request jsonb DEFAULT '{}'::jsonb NOT NULL,\n result jsonb,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid,\n owner_id uuid,\n CONSTRAINT plg_inventory_operations_kind_check CHECK ((kind = ANY (ARRAY['receive'::text, 'transfer'::text, 'adjust'::text, 'reserve'::text, 'confirm'::text, 'reverse'::text]))),\n CONSTRAINT plg_inventory_operations_status_check CHECK ((status = ANY (ARRAY['pending'::text, 'done'::text])))\n);\n\nALTER TABLE ONLY public.plg_inventory_operations FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_product_categories (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n parent_id uuid,\n is_active boolean DEFAULT true 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 unit_id uuid,\n owner_id uuid\n);\n\nALTER TABLE ONLY public.plg_inventory_product_categories FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_product_details (\n product_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n category_id uuid,\n measurement_unit_id uuid,\n purchase_unit_id uuid,\n conversion_factor numeric(14,4) DEFAULT 1 NOT NULL,\n supplier_id uuid,\n default_location_id uuid,\n purpose text,\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 public.plg_inventory_product_settings (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n min_quantity numeric(16,4) DEFAULT 0 NOT NULL,\n max_quantity numeric(16,4),\n measurement_unit_id uuid,\n default_location_id uuid,\n track_batches boolean DEFAULT false 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 unit_id uuid,\n owner_id uuid,\n CONSTRAINT plg_inventory_product_settings_max_quantity_check CHECK (((max_quantity IS NULL) OR (max_quantity >= (0)::numeric))),\n CONSTRAINT plg_inventory_product_settings_min_quantity_check CHECK ((min_quantity >= (0)::numeric))\n);\n\nALTER TABLE ONLY public.plg_inventory_product_settings FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_recipe_groups (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n recipe_id uuid NOT NULL,\n name text NOT NULL,\n preparation_notes text,\n display_order integer DEFAULT 0 NOT NULL,\n estimated_minutes integer,\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 public.plg_inventory_recipe_ingredients (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n recipe_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n quantity numeric(14,4) NOT NULL,\n unit_id uuid,\n display_order integer DEFAULT 0,\n notes text,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n group_id uuid\n);\n\nCREATE TABLE public.plg_inventory_recipes (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n description text,\n product_id uuid,\n yield_quantity numeric(14,4) DEFAULT 1,\n yield_unit_id uuid,\n preparation_time_minutes integer,\n instructions text,\n is_active boolean DEFAULT true 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 metadata jsonb,\n unit_id uuid,\n owner_id uuid\n);\n\nALTER TABLE ONLY public.plg_inventory_recipes FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_reservations (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n idempotency_key text NOT NULL,\n line_no integer DEFAULT 1 NOT NULL,\n source_type text NOT NULL,\n source_id uuid NOT NULL,\n product_id uuid NOT NULL,\n stock_location_id uuid NOT NULL,\n batch_number text,\n expiration_date date,\n quantity numeric(16,4) NOT NULL,\n measurement_unit_id uuid,\n status text DEFAULT 'reserved'::text NOT NULL,\n movement_id uuid,\n reversal_movement_id uuid,\n reason text,\n confirmed_at timestamp with time zone,\n confirmed_by uuid,\n reversed_at timestamp with time zone,\n reversed_by 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 unit_id uuid NOT NULL,\n owner_id uuid,\n CONSTRAINT plg_inventory_reservations_quantity_check CHECK ((quantity > (0)::numeric)),\n CONSTRAINT plg_inventory_reservations_status_check CHECK ((status = ANY (ARRAY['reserved'::text, 'confirmed'::text, 'reversed'::text])))\n);\n\nALTER TABLE ONLY public.plg_inventory_reservations FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_stock_locations (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n name text NOT NULL,\n description text,\n is_active boolean DEFAULT true NOT NULL,\n unit_id uuid 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 owner_id uuid,\n code text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL\n);\n\nALTER TABLE ONLY public.plg_inventory_stock_locations FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_stock_movements (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n quantity numeric(14,4) NOT NULL,\n kind text NOT NULL,\n unit_cost numeric(16,4) DEFAULT 0 NOT NULL,\n total_cost numeric(16,4) DEFAULT 0 NOT NULL,\n source_location_id uuid NOT NULL,\n destination_location_id uuid,\n supplier_id uuid,\n document_number text,\n reason text,\n notes text,\n movement_date date DEFAULT CURRENT_DATE NOT NULL,\n user_id uuid,\n batch_number text,\n expiration_date date,\n metadata jsonb DEFAULT '{}'::jsonb,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid NOT NULL,\n owner_id uuid,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n stock_location_id uuid GENERATED ALWAYS AS (source_location_id) STORED,\n movement_type text GENERATED ALWAYS AS (kind) STORED,\n document_type text,\n reverses_movement_id uuid,\n idempotency_key text,\n line_no integer DEFAULT 1 NOT NULL,\n operation_id uuid,\n source_item_type text,\n source_item_id uuid,\n measurement_unit_id uuid,\n CONSTRAINT plg_inventory_stock_movements_cost_check CHECK (((unit_cost >= (0)::numeric) AND (total_cost >= (0)::numeric))),\n CONSTRAINT plg_inventory_stock_movements_kind_check CHECK ((kind = ANY (ARRAY['in'::text, 'out'::text, 'transfer'::text, 'adjust'::text, 'reverse'::text]))),\n CONSTRAINT plg_inventory_stock_movements_quantity_check CHECK ((quantity <> (0)::numeric)),\n CONSTRAINT plg_inventory_stock_movements_reverse_check CHECK (((kind = 'reverse'::text) = (reverses_movement_id IS NOT NULL))),\n CONSTRAINT plg_inventory_stock_movements_sign_check CHECK ((((kind = 'in'::text) AND (quantity > (0)::numeric)) OR ((kind = 'out'::text) AND (quantity < (0)::numeric)) OR ((kind = 'transfer'::text) AND (quantity < (0)::numeric)) OR (kind = ANY (ARRAY['adjust'::text, 'reverse'::text])))),\n CONSTRAINT plg_inventory_stock_movements_transfer_check CHECK ((((kind = 'transfer'::text) AND (destination_location_id IS NOT NULL) AND (destination_location_id <> source_location_id)) OR ((kind = ANY (ARRAY['in'::text, 'out'::text, 'adjust'::text])) AND (destination_location_id IS NULL)) OR (kind = 'reverse'::text)))\n);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_stock_positions (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n quantity numeric(14,4) NOT NULL,\n unit_cost numeric(16,4) DEFAULT 0 NOT NULL,\n stock_location_id uuid NOT NULL,\n batch_number text,\n expiration_date date,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n measurement_unit_id uuid,\n unit_type text DEFAULT 'base'::text NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid NOT NULL,\n owner_id uuid,\n CONSTRAINT plg_inventory_stock_positions_quantity_check CHECK ((quantity >= (0)::numeric))\n);\n\nALTER TABLE ONLY public.plg_inventory_stock_positions FORCE ROW LEVEL SECURITY;\n\nCREATE TABLE public.plg_inventory_unit_conversions (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n from_unit_id uuid NOT NULL,\n to_unit_id uuid NOT NULL,\n factor numeric(20,8) NOT NULL,\n product_id uuid,\n notes text,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n unit_id uuid,\n owner_id uuid,\n CONSTRAINT plg_inventory_unit_conversions_check CHECK ((from_unit_id <> to_unit_id)),\n CONSTRAINT plg_inventory_unit_conversions_factor_check CHECK ((factor > (0)::numeric))\n);\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions FORCE ROW LEVEL SECURITY;\n\n\n-- ── function ────────────────────────────────────────────────────────────\n\nCREATE FUNCTION app.inventory_apply_to_position(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date, p_effect numeric, p_unit_cost numeric, p_measurement_unit uuid, OUT o_quantity numeric, OUT o_unit_cost numeric) RETURNS record\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_unit uuid;\n v_pos record;\n v_new_qty numeric;\n v_new_cost numeric;\nBEGIN\n SELECT l.unit_id INTO v_unit FROM public.plg_inventory_stock_locations l WHERE l.id = p_location AND l.tenant_id = p_tenant;\n SELECT p.id, p.quantity, p.unit_cost INTO v_pos\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)\n FOR UPDATE;\n IF v_pos.id IS NULL THEN\n IF p_effect < 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock (no position for product % at location %)', p_product, p_location USING ERRCODE = '23514';\n END IF;\n INSERT INTO public.plg_inventory_stock_positions\n (tenant_id, unit_id, product_id, stock_location_id, batch_number, expiration_date, quantity, unit_cost, measurement_unit_id)\n VALUES (p_tenant, v_unit, p_product, p_location, p_batch, p_expiry, p_effect, coalesce(p_unit_cost, 0), p_measurement_unit)\n RETURNING plg_inventory_stock_positions.quantity, plg_inventory_stock_positions.unit_cost INTO o_quantity, o_unit_cost;\n RETURN;\n END IF;\n v_new_qty := v_pos.quantity + p_effect;\n IF v_new_qty < 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock (product % at location %: % on hand, % requested)', p_product, p_location, v_pos.quantity, -p_effect USING ERRCODE = '23514';\n END IF;\n IF p_effect > 0 AND v_new_qty > 0 THEN\n v_new_cost := (v_pos.quantity * v_pos.unit_cost + p_effect * coalesce(p_unit_cost, v_pos.unit_cost)) / v_new_qty;\n ELSE\n v_new_cost := v_pos.unit_cost;\n END IF;\n UPDATE public.plg_inventory_stock_positions p\n SET quantity = v_new_qty, unit_cost = round(v_new_cost, 4), unit_id = v_unit,\n measurement_unit_id = coalesce(p.measurement_unit_id, p_measurement_unit)\n WHERE p.id = v_pos.id\n RETURNING p.quantity, p.unit_cost INTO o_quantity, o_unit_cost;\nEND $$;\n\nCREATE FUNCTION app.inventory_authorize_location(p_tenant uuid, p_location uuid, p_perm text) RETURNS uuid\n LANGUAGE plpgsql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE v_loc record;\nBEGIN\n IF p_location IS NULL THEN\n RAISE EXCEPTION 'inventory: a stock location is required' USING ERRCODE = '22023';\n END IF;\n SELECT id, unit_id, is_active INTO v_loc FROM public.plg_inventory_stock_locations WHERE id = p_location AND tenant_id = p_tenant;\n -- unknown, another tenant's, or outside the caller's units: one answer, no leak\n IF v_loc.id IS NULL OR NOT app.has_unit(v_loc.unit_id) THEN\n RAISE EXCEPTION 'inventory: no access to stock location %', p_location USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission(p_perm, v_loc.unit_id) THEN\n RAISE EXCEPTION 'inventory: % required at the unit of stock location %', p_perm, p_location USING ERRCODE = '42501';\n END IF;\n RETURN v_loc.unit_id;\nEND $$;\n\nCREATE FUNCTION app.inventory_available(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date) RETURNS numeric\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT coalesce((SELECT p.quantity FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)), 0)\n - coalesce((SELECT sum(r.quantity) FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.product_id = p_product AND r.stock_location_id = p_location\n AND coalesce(r.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(r.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)\n AND r.status = 'reserved'), 0);\n$$;\n\nCREATE FUNCTION app.inventory_begin_operation(p_tenant uuid, p_kind text, p_key text, p_request jsonb, OUT op_id uuid, OUT existing jsonb) RETURNS record\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n -- from here to inventory_finish_operation the ledger tables accept writes\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n INSERT INTO public.plg_inventory_operations (tenant_id, kind, idempotency_key, actor_id, request)\n VALUES (p_tenant, p_kind, p_key, auth.uid(), coalesce(p_request, '{}'::jsonb))\n ON CONFLICT (tenant_id, kind, idempotency_key) DO NOTHING\n RETURNING id INTO op_id;\n IF op_id IS NULL THEN\n SELECT result INTO existing FROM public.plg_inventory_operations\n WHERE tenant_id = p_tenant AND kind = p_kind AND idempotency_key = p_key;\n IF existing IS NULL THEN\n -- a visible row without a result can only be a call that failed after\n -- committing nothing — impossible in one transaction — or a concurrent\n -- call still in flight after the wait; refuse rather than double-apply\n RAISE EXCEPTION 'inventory: operation % is still in progress', p_key USING ERRCODE = '55P03';\n END IF;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n END IF;\nEND $$;\n\nCREATE FUNCTION app.inventory_check_lines(p_lines jsonb) RETURNS void\n LANGUAGE plpgsql IMMUTABLE\n AS $$\nBEGIN\n IF p_lines IS NULL OR jsonb_typeof(p_lines) <> 'array' OR jsonb_array_length(p_lines) = 0 THEN\n RAISE EXCEPTION 'inventory: lines must be a non-empty JSON array' USING ERRCODE = '22023';\n END IF;\nEND $$;\n\nCREATE FUNCTION app.inventory_consume_order_item(p_tenant uuid, p_order uuid, p_order_item uuid, p_unit uuid, p_product uuid, p_quantity numeric, p_actor uuid DEFAULT NULL::uuid) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_key text := 'order_item:' || p_order_item::text;\n v_op record;\n v_reservation record;\n v_recipe record;\n v_requirement jsonb;\n v_requirements jsonb := '[]'::jsonb;\n v_parsed record;\n v_position record;\n v_location uuid;\n v_remaining numeric;\n v_available numeric;\n v_take numeric;\n v_reservation_cost numeric;\n v_movement uuid;\n v_line_no integer := 0;\n v_movements jsonb := '[]'::jsonb;\n v_mode text := 'direct_product';\nBEGIN\n IF p_tenant IS NULL OR p_order IS NULL OR p_order_item IS NULL OR p_product IS NULL\n OR coalesce(p_quantity, 0) <= 0 THEN\n RAISE EXCEPTION 'inventory: invalid order item consumption request' USING ERRCODE = '22023';\n END IF;\n\n -- Compatibility with the former browser bridge. If it already reserved the\n -- recipe lines, finish those exact lines instead of resolving the recipe a\n -- second time. The confirm operation key is shared by both implementations.\n IF EXISTS (\n SELECT 1 FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.idempotency_key = v_key\n ) THEN\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n p_tenant, 'confirm', v_key,\n jsonb_build_object('source', 'order.completed', 'order_id', p_order, 'actor_id', p_actor)\n );\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR v_reservation IN\n SELECT r.* FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = p_tenant AND r.idempotency_key = v_key\n ORDER BY r.line_no FOR UPDATE\n LOOP\n IF v_reservation.status = 'reserved' THEN\n SELECT p.unit_cost INTO v_reservation_cost\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant\n AND p.product_id = v_reservation.product_id\n AND p.stock_location_id = v_reservation.stock_location_id\n AND coalesce(p.batch_number, '') = coalesce(v_reservation.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_reservation.expiration_date, 'infinity'::date);\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n document_number, source_item_type, source_item_id, idempotency_key,\n line_no, operation_id, user_id, metadata)\n VALUES\n (p_tenant, v_reservation.product_id, 'out', -v_reservation.quantity,\n coalesce(v_reservation_cost, 0), v_reservation.stock_location_id,\n v_reservation.batch_number, v_reservation.expiration_date,\n v_reservation.measurement_unit_id, 'consumption', p_order::text,\n 'order_item', p_order_item, v_key, v_reservation.line_no, v_op.op_id,\n p_actor, coalesce(v_reservation.metadata, '{}'::jsonb)\n || jsonb_build_object('source', 'order.completed', 'reservation_id', v_reservation.id))\n RETURNING id INTO v_movement;\n\n UPDATE public.plg_inventory_reservations r\n SET status = 'confirmed', confirmed_at = now(), confirmed_by = p_actor,\n movement_id = v_movement\n WHERE r.id = v_reservation.id AND r.status = 'reserved';\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n END IF;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n p_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm',\n 'idempotency_key', v_key, 'source_type', 'order_item',\n 'source_id', p_order_item, 'status', 'confirmed',\n 'mode', 'legacy_reservation', 'movements', v_movements),\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'actor_id', p_actor)\n );\n END IF;\n\n SELECT r.id, r.yield_quantity INTO v_recipe\n FROM public.plg_inventory_recipes r\n WHERE r.tenant_id = p_tenant\n AND r.product_id = p_product\n AND r.is_active\n ORDER BY r.updated_at DESC, r.id\n LIMIT 1;\n\n IF v_recipe.id IS NOT NULL THEN\n IF coalesce(v_recipe.yield_quantity, 0) <= 0 THEN\n RAISE EXCEPTION 'inventory: recipe % has an invalid yield quantity', v_recipe.id\n USING ERRCODE = '22023';\n END IF;\n\n SELECT coalesce(jsonb_agg(jsonb_build_object(\n 'product_id', x.product_id,\n 'quantity', round(x.quantity * p_quantity / v_recipe.yield_quantity, 4),\n 'measurement_unit_id', x.unit_id,\n 'recipe_id', v_recipe.id\n ) ORDER BY x.first_order), '[]'::jsonb)\n INTO v_requirements\n FROM (\n SELECT i.product_id, i.unit_id, sum(i.quantity) AS quantity,\n min(i.display_order) AS first_order\n FROM public.plg_inventory_recipe_ingredients i\n WHERE i.tenant_id = p_tenant AND i.recipe_id = v_recipe.id\n GROUP BY i.product_id, i.unit_id\n ) x;\n\n IF jsonb_array_length(v_requirements) = 0 THEN\n RAISE EXCEPTION 'inventory: recipe % has no ingredients', v_recipe.id\n USING ERRCODE = '22023';\n END IF;\n v_mode := 'recipe';\n ELSE\n v_requirements := jsonb_build_array(jsonb_build_object(\n 'product_id', p_product,\n 'quantity', round(p_quantity, 4),\n 'measurement_unit_id', NULL\n ));\n END IF;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n p_tenant, 'confirm', v_key,\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'product_id', p_product,\n 'quantity', p_quantity, 'mode', v_mode, 'actor_id', p_actor)\n );\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR v_requirement IN SELECT value FROM jsonb_array_elements(v_requirements)\n LOOP\n SELECT * INTO v_parsed FROM app.inventory_parse_line(\n p_tenant,\n jsonb_strip_nulls(jsonb_build_object(\n 'product_id', v_requirement ->> 'product_id',\n 'quantity', v_requirement ->> 'quantity',\n 'measurement_unit_id', v_requirement ->> 'measurement_unit_id'\n )),\n 'positive'\n );\n\n v_remaining := round(v_parsed.quantity, 4);\n IF v_remaining <= 0 THEN\n RAISE EXCEPTION 'inventory: order item % produced a zero stock requirement', p_order_item\n USING ERRCODE = '22023';\n END IF;\n\n v_location := NULL;\n SELECT candidate.location_id INTO v_location\n FROM (\n SELECT s.default_location_id AS location_id,\n CASE WHEN p_unit IS NOT NULL AND s.unit_id = p_unit THEN 1 ELSE 2 END AS priority\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = p_tenant\n AND s.product_id = v_parsed.product_id\n AND s.default_location_id IS NOT NULL\n AND (s.unit_id IS NULL OR s.unit_id = p_unit)\n UNION ALL\n SELECT d.default_location_id, 3\n FROM public.plg_inventory_product_details d\n WHERE d.tenant_id = p_tenant\n AND d.product_id = v_parsed.product_id\n AND d.default_location_id IS NOT NULL\n UNION ALL\n SELECT l.id, 4\n FROM public.plg_inventory_stock_locations l\n WHERE l.tenant_id = p_tenant AND l.is_active\n ) candidate\n JOIN public.plg_inventory_stock_locations l\n ON l.id = candidate.location_id\n AND l.tenant_id = p_tenant\n AND l.is_active\n WHERE p_unit IS NULL OR l.unit_id = p_unit\n ORDER BY candidate.priority, l.created_at, l.id\n LIMIT 1;\n\n IF v_location IS NULL THEN\n RAISE EXCEPTION 'inventory: product % has no active stock location for order unit %',\n v_parsed.product_id, p_unit USING ERRCODE = '22023';\n END IF;\n\n FOR v_position IN\n SELECT p.*\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant\n AND p.product_id = v_parsed.product_id\n AND p.stock_location_id = v_location\n AND p.quantity > 0\n ORDER BY p.expiration_date NULLS LAST, p.created_at, p.id\n FOR UPDATE\n LOOP\n v_available := app.inventory_available(\n p_tenant, v_position.product_id, v_position.stock_location_id,\n v_position.batch_number, v_position.expiration_date\n );\n CONTINUE WHEN v_available <= 0;\n v_take := least(v_remaining, v_available);\n v_line_no := v_line_no + 1;\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n document_number, source_item_type, source_item_id, idempotency_key,\n line_no, operation_id, user_id, metadata)\n VALUES\n (p_tenant, v_parsed.product_id, 'out', -v_take,\n coalesce(v_position.unit_cost, 0), v_location,\n v_position.batch_number, v_position.expiration_date,\n coalesce(v_position.measurement_unit_id, v_parsed.measurement_unit_id),\n 'consumption', p_order::text, 'order_item', p_order_item, v_key,\n v_line_no, v_op.op_id, p_actor,\n jsonb_strip_nulls(jsonb_build_object(\n 'source', 'order.completed',\n 'mode', v_mode,\n 'recipe_id', v_requirement ->> 'recipe_id',\n 'declared', v_parsed.declared\n )))\n RETURNING id INTO v_movement;\n\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n v_remaining := round(v_remaining - v_take, 4);\n EXIT WHEN v_remaining <= 0;\n END LOOP;\n\n IF v_remaining > 0 THEN\n RAISE EXCEPTION 'inventory: insufficient stock for product % at location % (% missing)',\n v_parsed.product_id, v_location, v_remaining USING ERRCODE = '23514';\n END IF;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n p_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm',\n 'idempotency_key', v_key, 'source_type', 'order_item',\n 'source_id', p_order_item, 'status', 'confirmed', 'mode', v_mode,\n 'recipe_id', v_recipe.id, 'movements', v_movements),\n jsonb_build_object('source', 'order.completed', 'order_id', p_order,\n 'order_item_id', p_order_item, 'actor_id', p_actor,\n 'movement_count', v_line_no, 'mode', v_mode)\n );\nEND $$;\n\nCREATE FUNCTION app.inventory_default_variant(p_tenant uuid, p_product uuid) RETURNS uuid\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT v.id\n FROM public.product_variants v\n WHERE v.tenant_id = p_tenant\n AND v.product_id = p_product\n AND v.is_active\n ORDER BY (v.is_default IS TRUE) DESC, v.sort_order, v.created_at\n LIMIT 1\n$$;\n\nCREATE FUNCTION app.inventory_finish_operation(p_tenant uuid, p_op uuid, p_kind text, p_key text, p_result jsonb, p_audit jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n UPDATE public.plg_inventory_operations SET status = 'done', result = p_result WHERE id = p_op;\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n INSERT INTO public.audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant, auth.uid(), 'inventory.' || p_kind, 'inventory.operation', p_op::text,\n jsonb_build_object('idempotency_key', p_key) || coalesce(p_audit, '{}'::jsonb));\n RETURN p_result;\nEND $$;\n\nCREATE FUNCTION app.inventory_internal_only() RETURNS trigger\n LANGUAGE plpgsql\n AS $$\nBEGIN\n IF coalesce(current_setting('fayz.inventory_internal', true), 'off') <> 'on' THEN\n RAISE EXCEPTION 'inventory: % is written only through the inventory RPCs (inventory_receive / _transfer / _adjust / _reserve / _confirm / _reverse)', TG_TABLE_NAME\n USING ERRCODE = '55000';\n END IF;\n IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;\n RETURN NEW;\nEND $$;\n\nCREATE FUNCTION app.inventory_locations_before_update() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n IF NEW.unit_id IS DISTINCT FROM OLD.unit_id\n AND EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = OLD.tenant_id\n AND (m.source_location_id = OLD.id OR m.destination_location_id = OLD.id)) THEN\n RAISE EXCEPTION 'inventory: a stock location with movements cannot change unit (deactivate it and create a new one)'\n USING ERRCODE = '55000';\n END IF;\n IF NEW.tenant_id IS DISTINCT FROM OLD.tenant_id THEN\n RAISE EXCEPTION 'inventory: a stock location cannot change tenant' USING ERRCODE = '55000';\n END IF;\n RETURN NEW;\nEND $$;\n\nCREATE FUNCTION app.inventory_movement_json(p_id uuid) RETURNS jsonb\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT jsonb_build_object(\n 'id', m.id, 'line_no', m.line_no, 'kind', m.kind, 'product_id', m.product_id, 'quantity', m.quantity,\n 'unit_cost', m.unit_cost, 'total_cost', m.total_cost,\n 'source_location_id', m.source_location_id, 'destination_location_id', m.destination_location_id,\n 'batch_number', m.batch_number, 'expiration_date', m.expiration_date,\n 'measurement_unit_id', m.measurement_unit_id, 'reverses_movement_id', m.reverses_movement_id,\n 'source_item_type', m.source_item_type, 'source_item_id', m.source_item_id)\n FROM public.plg_inventory_stock_movements m WHERE m.id = p_id;\n$$;\n\nCREATE FUNCTION app.inventory_movement_source_required() RETURNS trigger\n LANGUAGE plpgsql\n AS $$\nBEGIN\n IF NEW.source_location_id IS NULL THEN\n RAISE EXCEPTION 'inventory: a stock movement must name the location it moves from'\n USING ERRCODE = '23514';\n END IF;\n RETURN NEW;\nEND $$;\n\nCREATE FUNCTION app.inventory_movements_after_insert() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_prev text := coalesce(current_setting('fayz.inventory_internal', true), 'off');\n r record;\nBEGIN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.source_location_id, NEW.batch_number, NEW.expiration_date,\n NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n PERFORM app.inventory_sync_archetype_balance(NEW.tenant_id, NEW.product_id, NEW.source_location_id, NEW.quantity);\n\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT * INTO r FROM app.inventory_apply_to_position(\n NEW.tenant_id, NEW.product_id, NEW.destination_location_id, NEW.batch_number, NEW.expiration_date,\n -NEW.quantity, NEW.unit_cost, NEW.measurement_unit_id);\n PERFORM app.inventory_sync_archetype_balance(NEW.tenant_id, NEW.product_id, NEW.destination_location_id, -NEW.quantity);\n END IF;\n\n PERFORM set_config('fayz.inventory_internal', v_prev, true);\n RETURN NULL;\nEND $$;\n\nCREATE FUNCTION app.inventory_movements_append_only() RETURNS trigger\n LANGUAGE plpgsql\n AS $$\nDECLARE\n v_old jsonb;\n v_new jsonb;\n k text;\nBEGIN\n IF TG_OP = 'UPDATE' THEN\n v_old := to_jsonb(OLD);\n v_new := to_jsonb(NEW);\n FOREACH k IN ARRAY ARRAY['unit_id', 'owner_id', 'updated_at'] LOOP\n v_old := v_old - k;\n v_new := v_new - k;\n END LOOP;\n -- GENERATED columns read NULL in NEW inside a BEFORE trigger: Postgres\n -- computes them after these run. This table has two — the compat mirrors\n -- 107 left behind for stock_location_id and movement_type — so comparing\n -- them would report a change on every row and refuse every backfill.\n -- They are derived from the columns already being compared anyway.\n FOR k IN\n SELECT a.attname FROM pg_attribute a\n WHERE a.attrelid = TG_RELID AND a.attnum > 0\n AND NOT a.attisdropped AND a.attgenerated <> ''\n LOOP\n v_old := v_old - k;\n v_new := v_new - k;\n END LOOP;\n IF v_old = v_new\n AND (OLD.unit_id IS NULL OR NEW.unit_id IS NOT DISTINCT FROM OLD.unit_id)\n AND (OLD.owner_id IS NULL OR NEW.owner_id IS NOT DISTINCT FROM OLD.owner_id) THEN\n RETURN NEW;\n END IF;\n END IF;\n RAISE EXCEPTION 'inventory: stock movements are append-only (write a reversal instead)' USING ERRCODE = '55000';\nEND $$;\n\nCREATE FUNCTION app.inventory_movements_before_insert() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_src record;\n v_dst record;\nBEGIN\n IF NEW.tenant_id IS NULL THEN\n RAISE EXCEPTION 'inventory: movement without tenant' USING ERRCODE = '22023';\n END IF;\n IF NEW.source_location_id IS NULL THEN\n RAISE EXCEPTION 'inventory: movement without a source location' USING ERRCODE = '22023';\n END IF;\n SELECT id, tenant_id, unit_id, is_active INTO v_src FROM public.plg_inventory_stock_locations WHERE id = NEW.source_location_id;\n IF v_src.id IS NULL OR v_src.tenant_id <> NEW.tenant_id THEN\n RAISE EXCEPTION 'inventory: source location % does not belong to the tenant', NEW.source_location_id USING ERRCODE = '22023';\n END IF;\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT id, tenant_id, unit_id, is_active INTO v_dst FROM public.plg_inventory_stock_locations WHERE id = NEW.destination_location_id;\n IF v_dst.id IS NULL OR v_dst.tenant_id <> NEW.tenant_id THEN\n RAISE EXCEPTION 'inventory: destination location % does not belong to the tenant', NEW.destination_location_id USING ERRCODE = '22023';\n END IF;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.products p WHERE p.id = NEW.product_id AND p.tenant_id = NEW.tenant_id) THEN\n RAISE EXCEPTION 'inventory: product % does not belong to the tenant', NEW.product_id USING ERRCODE = '22023';\n END IF;\n -- the unit of the ledger row is the unit of the location whose stock moves first\n NEW.unit_id := v_src.unit_id;\n NEW.unit_cost := coalesce(NEW.unit_cost, 0);\n NEW.total_cost := abs(NEW.quantity) * NEW.unit_cost;\n NEW.user_id := coalesce(NEW.user_id, auth.uid());\n NEW.movement_date := coalesce(NEW.movement_date, current_date);\n NEW.metadata := coalesce(NEW.metadata, '{}'::jsonb);\n NEW.batch_number := nullif(btrim(NEW.batch_number), '');\n RETURN NEW;\nEND $$;\n\nCREATE FUNCTION app.inventory_parse_line(p_tenant uuid, p_line jsonb, p_mode text DEFAULT 'positive'::text, OUT product_id uuid, OUT quantity numeric, OUT unit_cost numeric, OUT batch_number text, OUT expiration_date date, OUT measurement_unit_id uuid, OUT declared jsonb, OUT notes text) RETURNS record\n LANGUAGE plpgsql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_product uuid;\n v_declared_unit uuid;\n v_stock_unit uuid;\n v_declared_qty numeric;\n v_qty numeric;\n v_cost numeric;\n v_batch text;\n v_expiry date;\nBEGIN\n BEGIN\n v_product := (p_line->>'product_id')::uuid;\n v_declared_qty := coalesce((p_line->>'quantity')::numeric, (p_line->>'delta')::numeric);\n v_cost := (p_line->>'unit_cost')::numeric;\n v_batch := nullif(btrim(coalesce(p_line->>'batch_number', p_line->>'batch', '')), '');\n v_expiry := coalesce((p_line->>'expiration_date')::date, (p_line->>'expiry')::date);\n v_declared_unit := (p_line->>'measurement_unit_id')::uuid;\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid line %: %', p_line, SQLERRM USING ERRCODE = '22023';\n END;\n IF v_product IS NULL THEN\n RAISE EXCEPTION 'inventory: line without product_id: %', p_line USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.products p WHERE p.id = v_product AND p.tenant_id = p_tenant) THEN\n RAISE EXCEPTION 'inventory: product % not found in this tenant', v_product USING ERRCODE = '22023';\n END IF;\n IF v_declared_qty IS NULL\n OR (p_mode = 'positive' AND v_declared_qty <= 0)\n OR (p_mode = 'signed' AND v_declared_qty = 0)\n OR (p_mode = 'absolute' AND v_declared_qty < 0) THEN\n RAISE EXCEPTION 'inventory: quantity must be % (line %)',\n CASE p_mode WHEN 'positive' THEN 'positive' WHEN 'signed' THEN 'non-zero' ELSE 'zero or positive' END, p_line USING ERRCODE = '22023';\n END IF;\n IF v_cost IS NOT NULL AND v_cost < 0 THEN\n RAISE EXCEPTION 'inventory: unit_cost cannot be negative (line %)', p_line USING ERRCODE = '22023';\n END IF;\n SELECT s.measurement_unit_id INTO v_stock_unit\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = p_tenant AND s.product_id = v_product AND s.unit_id IS NULL;\n v_qty := v_declared_qty;\n declared := '{}'::jsonb;\n IF v_declared_unit IS NOT NULL AND v_stock_unit IS NOT NULL AND v_declared_unit <> v_stock_unit THEN\n v_qty := public.inventory_convert(p_tenant, v_product, v_declared_qty, v_declared_unit, v_stock_unit);\n -- the cost was per declared unit; the ledger keeps cost per stock unit\n IF v_cost IS NOT NULL AND v_qty <> 0 THEN\n v_cost := round(v_cost * v_declared_qty / v_qty, 4);\n END IF;\n declared := jsonb_build_object('declared_quantity', v_declared_qty, 'declared_unit_id', v_declared_unit,\n 'declared_unit_cost', (p_line->>'unit_cost')::numeric);\n END IF;\n product_id := v_product;\n quantity := v_qty;\n unit_cost := v_cost;\n batch_number := v_batch;\n expiration_date := v_expiry;\n measurement_unit_id := coalesce(v_stock_unit, v_declared_unit);\n notes := p_line->>'notes';\nEND $$;\n\nCREATE FUNCTION app.inventory_position_json(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date) RETURNS jsonb\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT coalesce((\n SELECT jsonb_build_object('product_id', p.product_id, 'stock_location_id', p.stock_location_id, 'unit_id', p.unit_id,\n 'batch_number', p.batch_number, 'expiration_date', p.expiration_date,\n 'quantity', p.quantity, 'unit_cost', p.unit_cost)\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = p_tenant AND p.product_id = p_product AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(p_batch, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(p_expiry, 'infinity'::date)),\n jsonb_build_object('product_id', p_product, 'stock_location_id', p_location, 'batch_number', p_batch, 'expiration_date', p_expiry, 'quantity', 0, 'unit_cost', 0));\n$$;\n\nCREATE FUNCTION app.inventory_product_label(p_product uuid) RETURNS TABLE(name text, sku text)\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT p.name, p.sku FROM public.products p\n WHERE p.id = p_product AND p.tenant_id = app.current_tenant_id();\n$$;\n\nCREATE FUNCTION app.inventory_require_tenant() RETURNS uuid\n LANGUAGE plpgsql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE v_tenant uuid := app.current_tenant_id();\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n RETURN v_tenant;\nEND $$;\n\nCREATE FUNCTION app.inventory_reservation_json(p_id uuid) RETURNS jsonb\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\n SELECT jsonb_build_object(\n 'id', r.id, 'line_no', r.line_no, 'status', r.status, 'source_type', r.source_type, 'source_id', r.source_id,\n 'product_id', r.product_id, 'stock_location_id', r.stock_location_id, 'quantity', r.quantity,\n 'batch_number', r.batch_number, 'expiration_date', r.expiration_date,\n 'movement_id', r.movement_id, 'reversal_movement_id', r.reversal_movement_id)\n FROM public.plg_inventory_reservations r WHERE r.id = p_id;\n$$;\n\nCREATE FUNCTION app.inventory_reservation_one_per_source() RETURNS trigger\n LANGUAGE plpgsql\n SET search_path TO ''\n AS $$\nDECLARE v_existing record;\nBEGIN\n IF NEW.status = 'reversed' THEN\n RETURN NEW;\n END IF;\n SELECT r.id, r.idempotency_key, r.status INTO v_existing\n FROM public.plg_inventory_reservations r\n WHERE r.tenant_id = NEW.tenant_id\n AND r.source_type = NEW.source_type\n AND r.source_id = NEW.source_id\n AND r.line_no = NEW.line_no\n AND r.status <> 'reversed'\n AND r.id <> NEW.id\n LIMIT 1;\n IF FOUND THEN\n RAISE EXCEPTION\n 'inventory: % % line % is already consumed by reservation % (%) — reverse it before reserving again',\n NEW.source_type, NEW.source_id, NEW.line_no, v_existing.id, v_existing.status\n USING ERRCODE = '55000',\n HINT = 'inventory_reserve is idempotent by source item, not by idempotency key: a second key does not buy a second consumption (#203).';\n END IF;\n RETURN NEW;\nEND $$;\n\nCREATE FUNCTION app.inventory_sync_archetype_balance(p_tenant uuid, p_product uuid, p_location uuid, p_delta numeric) RETURNS void\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_variant uuid := app.inventory_default_variant(p_tenant, p_product);\n v_unit uuid;\nBEGIN\n IF v_variant IS NULL OR coalesce(p_delta, 0) = 0 THEN\n RETURN;\n END IF;\n SELECT l.unit_id INTO v_unit\n FROM public.plg_inventory_stock_locations l\n WHERE l.id = p_location AND l.tenant_id = p_tenant;\n\n PERFORM public.stock_apply(p_tenant, v_variant, v_unit, p_delta, 0, 'inventory');\nEND $$;\n\nCREATE FUNCTION app.trg_inventory_seed_units_for_tenant() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n PERFORM public.inventory_seed_measurement_units(NEW.id);\n RETURN NULL;\nEND $$;\n\nCREATE FUNCTION public.agent_inventory_upsert_recipe(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_denial jsonb;\n v_used int;\n v_recipe_id uuid;\n v_is_update boolean;\n v_name text;\n v_description text;\n v_instructions text;\n v_yield numeric;\n v_prep int;\n v_product_id uuid;\n v_product_hint text;\n v_item jsonb;\n v_iname text;\n v_qty numeric;\n v_pid uuid;\n v_order int := 0;\n v_resolved jsonb := '[]'::jsonb;\n v_unmatched jsonb := '[]'::jsonb;\n v_metadata jsonb;\n v_final_id uuid;\n v_final_name text;\nBEGIN\n -- ── payload ──────────────────────────────────────────────────────────────\n BEGIN\n v_recipe_id := NULLIF(p_payload->>'recipe_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n RETURN jsonb_build_object('ok', false, 'error', 'invalid recipe_id');\n END;\n v_is_update := v_recipe_id IS NOT NULL;\n v_name := btrim(p_payload->>'name');\n v_description := left(p_payload->>'description', 1000);\n v_instructions := left(p_payload->>'instructions', 8000);\n v_yield := COALESCE(NULLIF(p_payload->>'yield_quantity','')::numeric, 1);\n v_prep := NULLIF(p_payload->>'preparation_time_minutes','')::int;\n v_product_hint := btrim(COALESCE(p_payload->>'product_name',''));\n BEGIN\n v_product_id := NULLIF(p_payload->>'product_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n v_product_id := NULL;\n END;\n\n IF NOT v_is_update AND (v_name IS NULL OR v_name = '') THEN\n RETURN jsonb_build_object('ok', false, 'error', 'name is required to create a recipe');\n END IF;\n IF v_yield <= 0 THEN\n v_yield := 1;\n END IF;\n\n -- ── authorization: role → plan → recipes cap ─────────────────────────────\n SELECT count(*) INTO v_used FROM plg_inventory_recipes\n WHERE tenant_id = p_tenant_id AND is_active = true;\n v_denial := agent_guard(p_tenant_id, p_actor_user_id, 'inventory.recipes',\n CASE WHEN v_is_update THEN 'update' ELSE 'create' END,\n 'recipes', v_used, CASE WHEN v_is_update THEN 0 ELSE 1 END);\n IF v_denial IS NOT NULL THEN\n RETURN jsonb_build_object('ok', false, 'denial', v_denial);\n END IF;\n\n IF v_is_update THEN\n PERFORM 1 FROM plg_inventory_recipes\n WHERE id = v_recipe_id AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown recipe for this tenant');\n END IF;\n END IF;\n\n -- ── produced product: id must be this tenant's, else resolve by name ──────\n IF v_product_id IS NOT NULL THEN\n PERFORM 1 FROM products WHERE id = v_product_id AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN v_product_id := NULL; END IF;\n END IF;\n IF v_product_id IS NULL AND v_product_hint <> '' THEN\n SELECT p.id INTO v_product_id FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND lower(btrim(p.name)) = lower(v_product_hint)\n ORDER BY p.is_active DESC LIMIT 1;\n IF v_product_id IS NULL THEN\n -- Containment rather than ILIKE: the name is user text and % / _ in it\n -- would be read as wildcards.\n SELECT p.id INTO v_product_id FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND position(lower(v_product_hint) in lower(p.name)) > 0\n ORDER BY length(p.name) LIMIT 1;\n END IF;\n END IF;\n\n -- ── ingredients: name → products.id, unresolved ones set aside ───────────\n FOR v_item IN SELECT value FROM jsonb_array_elements(COALESCE(p_payload->'ingredients','[]'::jsonb))\n LOOP\n v_iname := btrim(COALESCE(v_item->>'name', v_item->>'product_name', ''));\n v_qty := COALESCE(NULLIF(v_item->>'quantity','')::numeric, 0);\n BEGIN\n v_pid := NULLIF(v_item->>'product_id','')::uuid;\n EXCEPTION WHEN OTHERS THEN\n v_pid := NULL;\n END;\n\n IF v_pid IS NOT NULL THEN\n PERFORM 1 FROM products WHERE id = v_pid AND tenant_id = p_tenant_id;\n IF NOT FOUND THEN v_pid := NULL; END IF;\n END IF;\n\n IF v_pid IS NULL AND v_iname <> '' THEN\n SELECT p.id INTO v_pid FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND lower(btrim(p.name)) = lower(v_iname)\n ORDER BY p.is_active DESC LIMIT 1;\n IF v_pid IS NULL THEN\n SELECT p.id INTO v_pid FROM products p\n WHERE p.tenant_id = p_tenant_id\n AND position(lower(v_iname) in lower(p.name)) > 0\n ORDER BY length(p.name) LIMIT 1;\n END IF;\n END IF;\n\n IF v_pid IS NULL OR v_qty <= 0 THEN\n v_unmatched := v_unmatched || jsonb_build_object(\n 'name', v_iname, 'quantity', v_qty, 'notes', NULLIF(v_item->>'notes',''));\n ELSE\n v_resolved := v_resolved || jsonb_build_object(\n 'product_id', v_pid, 'quantity', v_qty,\n 'notes', NULLIF(v_item->>'notes',''), 'display_order', v_order);\n v_order := v_order + 1;\n END IF;\n END LOOP;\n\n v_metadata := jsonb_strip_nulls(jsonb_build_object(\n 'unmatchedIngredients',\n CASE WHEN jsonb_array_length(v_unmatched) > 0 THEN v_unmatched ELSE NULL END,\n 'productHint',\n CASE WHEN v_product_id IS NULL AND v_product_hint <> '' THEN v_product_hint ELSE NULL END\n ));\n\n -- ── write + audit ────────────────────────────────────────────────────────\n IF v_is_update THEN\n UPDATE plg_inventory_recipes SET\n name = COALESCE(NULLIF(v_name,''), name),\n description = COALESCE(v_description, description),\n product_id = COALESCE(v_product_id, product_id),\n yield_quantity = COALESCE(NULLIF(NULLIF(p_payload->>'yield_quantity','')::numeric, 0), yield_quantity),\n preparation_time_minutes = COALESCE(v_prep, preparation_time_minutes),\n instructions = COALESCE(v_instructions, instructions),\n -- An edit that says nothing about ingredients must not erase the gaps the\n -- user still has to resolve.\n metadata = CASE WHEN p_payload ? 'ingredients' OR v_product_hint <> ''\n THEN v_metadata ELSE metadata END,\n updated_at = now()\n WHERE id = v_recipe_id AND tenant_id = p_tenant_id\n RETURNING id, name INTO v_final_id, v_final_name;\n ELSE\n INSERT INTO plg_inventory_recipes (\n tenant_id, name, description, product_id, yield_quantity,\n preparation_time_minutes, instructions, metadata\n ) VALUES (\n p_tenant_id, v_name, v_description, v_product_id, v_yield,\n v_prep, v_instructions, v_metadata\n )\n RETURNING id, name INTO v_final_id, v_final_name;\n END IF;\n\n -- \\`ingredients\\` REPLACES the list; omitting the key leaves the recipe's own.\n IF p_payload ? 'ingredients' THEN\n DELETE FROM plg_inventory_recipe_ingredients\n WHERE recipe_id = v_final_id AND tenant_id = p_tenant_id;\n INSERT INTO plg_inventory_recipe_ingredients (\n tenant_id, recipe_id, product_id, quantity, notes, display_order\n )\n SELECT p_tenant_id, v_final_id, (e->>'product_id')::uuid,\n (e->>'quantity')::numeric, NULLIF(e->>'notes',''), (e->>'display_order')::int\n FROM jsonb_array_elements(v_resolved) e;\n END IF;\n\n INSERT INTO audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (p_tenant_id, p_actor_user_id,\n CASE WHEN v_is_update THEN 'agent.updateRecipe' ELSE 'agent.createRecipe' END,\n 'inventory_recipe', v_final_id::text,\n jsonb_build_object('payload', p_payload));\n\n RETURN jsonb_build_object(\n 'ok', true,\n 'id', v_final_id,\n 'record', jsonb_build_object(\n 'ref', jsonb_build_object('id', v_final_id, 'resource', 'plg_inventory_recipes',\n 'archetype', 'inventory:recipe'),\n 'name', v_final_name,\n 'productId', v_product_id,\n 'ingredientCount', jsonb_array_length(v_resolved),\n 'unmatchedIngredients', v_unmatched,\n 'productHint', CASE WHEN v_product_id IS NULL THEN NULLIF(v_product_hint,'') ELSE NULL END\n )\n );\nEND;\n$$;\n\nCREATE FUNCTION public.app_product_stock_owner(p_tenant uuid) RETURNS text\n LANGUAGE sql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$ SELECT app.product_stock_owner(p_tenant) $$;\n\nCREATE FUNCTION public.inventory_adjust(p_location uuid, p_lines jsonb, p_reason text, p_idempotency_key text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'adjust:' || gen_random_uuid()::text);\n v_reason text := nullif(btrim(p_reason), '');\n v_op record;\n v_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_delta numeric;\n v_current numeric;\n v_target numeric;\n v_cost numeric;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: an adjustment needs a reason' USING ERRCODE = '22023';\n END IF;\n PERFORM app.inventory_check_lines(p_lines);\n v_unit := app.inventory_authorize_location(v_tenant, p_location, 'inventory.edit');\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'adjust', v_key,\n jsonb_build_object('location', p_location, 'lines', p_lines, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n IF v_line ? 'set_quantity' THEN\n -- absolute: turn into a delta against the current position (in the stock unit)\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, (v_line - 'set_quantity') || jsonb_build_object('quantity', v_line->'set_quantity'), 'absolute');\n v_target := v_ln.quantity;\n IF v_target < 0 THEN\n RAISE EXCEPTION 'inventory: set_quantity cannot be negative (line %)', v_line USING ERRCODE = '22023';\n END IF;\n SELECT coalesce(p.quantity, 0) INTO v_current FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n v_delta := v_target - coalesce(v_current, 0);\n IF v_delta = 0 THEN\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n CONTINUE;\n END IF;\n ELSE\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'signed');\n v_delta := v_ln.quantity;\n END IF;\n IF v_delta < 0 THEN\n IF app.inventory_available(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date) < -v_delta THEN\n RAISE EXCEPTION 'inventory: adjustment would take product % at location % below its available quantity',\n v_ln.product_id, p_location USING ERRCODE = '23514';\n END IF;\n END IF;\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, reason, notes, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'adjust', v_delta, coalesce(v_ln.unit_cost, v_cost, 0), p_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n 'adjustment', v_reason, v_ln.notes, v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'adjust', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'adjust', 'idempotency_key', v_key,\n 'location_id', p_location, 'unit_id', v_unit, 'reason', v_reason, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('location_id', p_location, 'unit_id', v_unit, 'reason', v_reason, 'lines', v_no));\nEND $$;\n\nCREATE FUNCTION public.inventory_close_count_session(p_session_id uuid, p_reason text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_session plg_inventory_count_sessions%ROWTYPE;\n v_item plg_inventory_count_items%ROWTYPE;\n v_delta numeric;\n v_movement_id uuid;\n v_reason text;\n v_emitted int := 0;\nBEGIN\n -- The lock is what makes two simultaneous closes serialise instead of both\n -- reading \\`counting\\` and both emitting.\n SELECT * INTO v_session FROM plg_inventory_count_sessions\n WHERE id = p_session_id FOR UPDATE;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown count session');\n END IF;\n IF v_session.tenant_id NOT IN (SELECT public.user_tenant_ids()) THEN\n RAISE EXCEPTION 'inventory_close_count_session: not a member of this tenant';\n END IF;\n\n IF v_session.status = 'closed' THEN\n RETURN jsonb_build_object('ok', true, 'session_id', p_session_id,\n 'status', 'closed', 'already_closed', true, 'adjustments_created', 0);\n END IF;\n IF v_session.status = 'cancelled' THEN\n RETURN jsonb_build_object('ok', false, 'error', 'this count was cancelled');\n END IF;\n\n v_reason := COALESCE(NULLIF(btrim(COALESCE(p_reason, '')), ''), 'Stock count');\n\n FOR v_item IN\n SELECT * FROM plg_inventory_count_items\n WHERE session_id = p_session_id\n AND counted_quantity IS NOT NULL\n AND counted_quantity <> system_quantity\n AND movement_id IS NULL\n ORDER BY id\n FOR UPDATE\n LOOP\n v_delta := v_item.counted_quantity - v_item.system_quantity;\n\n INSERT INTO plg_inventory_stock_movements (\n tenant_id, product_id, quantity, movement_type, unit_cost, total_cost,\n stock_location_id, reason, movement_date, user_id, metadata\n ) VALUES (\n v_session.tenant_id, v_item.product_id, v_item.counted_quantity, 'adjustment',\n v_item.unit_cost, v_item.unit_cost * v_item.counted_quantity,\n v_session.stock_location_id, v_reason, CURRENT_DATE, auth.uid(),\n jsonb_build_object(\n 'countSessionId', p_session_id,\n 'countItemId', v_item.id,\n 'systemQuantity', v_item.system_quantity,\n 'countedQuantity', v_item.counted_quantity,\n 'variance', v_delta\n )\n )\n RETURNING id INTO v_movement_id;\n\n UPDATE plg_inventory_count_items\n SET movement_id = v_movement_id, updated_at = now()\n WHERE id = v_item.id;\n\n -- The variance lands on the untracked slot; batch slots keep their lots.\n INSERT INTO plg_inventory_stock_positions (\n tenant_id, product_id, stock_location_id, quantity, unit_cost\n ) VALUES (\n v_session.tenant_id, v_item.product_id, v_session.stock_location_id,\n v_delta, v_item.unit_cost\n )\n ON CONFLICT (tenant_id, product_id, stock_location_id, batch_number, expiration_date)\n DO UPDATE SET\n quantity = plg_inventory_stock_positions.quantity + EXCLUDED.quantity,\n updated_at = now();\n\n v_emitted := v_emitted + 1;\n END LOOP;\n\n UPDATE plg_inventory_count_sessions\n SET status = 'closed', closed_at = now(), closed_by = auth.uid(), updated_at = now()\n WHERE id = p_session_id;\n\n RETURN jsonb_build_object('ok', true, 'session_id', p_session_id,\n 'status', 'closed', 'already_closed', false, 'adjustments_created', v_emitted);\nEND;\n$$;\n\nCREATE FUNCTION public.inventory_confirm(p_idempotency_key text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := nullif(btrim(p_idempotency_key), '');\n v_op record;\n r record;\n v_unit uuid;\n v_id uuid;\n v_cost numeric;\n v_n integer := 0;\n v_movements jsonb := '[]'::jsonb;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_source_type text; v_source_id uuid;\nBEGIN\n IF v_key IS NULL THEN\n RAISE EXCEPTION 'inventory: idempotency_key is required' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key) THEN\n RAISE EXCEPTION 'inventory: no reservation with key % in this tenant', v_key USING ERRCODE = '22023';\n END IF;\n -- authorization first, before the operation row exists\n FOR r IN SELECT DISTINCT stock_location_id FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key LOOP\n PERFORM app.inventory_authorize_location(v_tenant, r.stock_location_id, 'inventory.edit');\n END LOOP;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'confirm', v_key, jsonb_build_object('idempotency_key', v_key));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR r IN SELECT * FROM public.plg_inventory_reservations x\n WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no FOR UPDATE LOOP\n v_source_type := r.source_type; v_source_id := r.source_id;\n IF r.status = 'reserved' THEN\n -- CAS: only the row still reserved becomes a movement\n UPDATE public.plg_inventory_reservations x\n SET status = 'confirmed', confirmed_at = now(), confirmed_by = auth.uid()\n WHERE x.id = r.id AND x.status = 'reserved';\n IF FOUND THEN\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = r.product_id AND p.stock_location_id = r.stock_location_id\n AND coalesce(p.batch_number, '') = coalesce(r.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(r.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, source_item_type, source_item_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'out', -r.quantity, coalesce(v_cost, 0), r.stock_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'consumption', r.source_type || ':' || r.source_id::text, r.source_type, r.source_id, v_key, r.line_no, v_op.op_id,\n coalesce(r.metadata, '{}'::jsonb) || jsonb_build_object('reservation_id', r.id))\n RETURNING id INTO v_id;\n UPDATE public.plg_inventory_reservations x SET movement_id = v_id WHERE x.id = r.id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_n := v_n + 1;\n END IF;\n ELSIF r.status = 'reversed' AND r.movement_id IS NULL THEN\n RAISE EXCEPTION 'inventory: reservation % line % was reversed before confirmation', v_key, r.line_no USING ERRCODE = '55000';\n END IF;\n v_reservations := v_reservations || app.inventory_reservation_json(r.id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.stock_location_id, r.batch_number, r.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'confirm', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'confirm', 'idempotency_key', v_key,\n 'source_type', v_source_type, 'source_id', v_source_id, 'status', 'confirmed',\n 'movements', v_movements, 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('source_type', v_source_type, 'source_id', v_source_id, 'confirmed_lines', v_n));\nEND $$;\n\nCREATE FUNCTION public.inventory_convert(p_tenant uuid, p_product uuid, p_qty numeric, p_from_unit uuid, p_to_unit uuid) RETURNS numeric\n LANGUAGE plpgsql STABLE SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_factor numeric;\n v_kind_from text; v_kind_to text;\n v_base uuid;\n v_f1 numeric; v_f2 numeric;\nBEGIN\n IF p_tenant IS NULL OR p_from_unit IS NULL OR p_to_unit IS NULL THEN\n RAISE EXCEPTION 'inventory_convert: tenant, from_unit and to_unit are required' USING ERRCODE = '22023';\n END IF;\n -- a signed-in session converts only within its own tenant\n IF auth.uid() IS NOT NULL AND p_tenant IS DISTINCT FROM app.current_tenant_id() THEN\n RAISE EXCEPTION 'inventory_convert: not your tenant' USING ERRCODE = '42501';\n END IF;\n IF p_from_unit = p_to_unit THEN RETURN p_qty; END IF;\n\n -- direct (product-specific first, then tenant-wide)\n SELECT c.factor INTO v_factor FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND c.from_unit_id = p_from_unit AND c.to_unit_id = p_to_unit\n AND (c.product_id = p_product OR c.product_id IS NULL)\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_factor IS NOT NULL THEN RETURN p_qty * v_factor; END IF;\n -- inverse\n SELECT c.factor INTO v_factor FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND c.from_unit_id = p_to_unit AND c.to_unit_id = p_from_unit\n AND (c.product_id = p_product OR c.product_id IS NULL)\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_factor IS NOT NULL THEN RETURN p_qty / v_factor; END IF;\n\n -- one hop through the base unit of the (shared) kind\n SELECT kind INTO v_kind_from FROM public.plg_inventory_measurement_units WHERE id = p_from_unit AND tenant_id = p_tenant;\n SELECT kind INTO v_kind_to FROM public.plg_inventory_measurement_units WHERE id = p_to_unit AND tenant_id = p_tenant;\n IF v_kind_from IS NULL OR v_kind_to IS NULL OR v_kind_from <> v_kind_to THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n SELECT id INTO v_base FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND kind = v_kind_from AND is_base;\n IF v_base IS NULL OR v_base IN (p_from_unit, p_to_unit) THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n -- from → base\n SELECT CASE WHEN c.from_unit_id = p_from_unit THEN c.factor ELSE 1 / c.factor END INTO v_f1\n FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND (c.product_id = p_product OR c.product_id IS NULL)\n AND ((c.from_unit_id = p_from_unit AND c.to_unit_id = v_base) OR (c.from_unit_id = v_base AND c.to_unit_id = p_from_unit))\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n -- base → to\n SELECT CASE WHEN c.from_unit_id = v_base THEN c.factor ELSE 1 / c.factor END INTO v_f2\n FROM public.plg_inventory_unit_conversions c\n WHERE c.tenant_id = p_tenant AND (c.product_id = p_product OR c.product_id IS NULL)\n AND ((c.from_unit_id = v_base AND c.to_unit_id = p_to_unit) OR (c.from_unit_id = p_to_unit AND c.to_unit_id = v_base))\n ORDER BY (c.product_id IS NOT NULL) DESC LIMIT 1;\n IF v_f1 IS NULL OR v_f2 IS NULL THEN\n RAISE EXCEPTION 'inventory_convert: no conversion from % to % (tenant %, product %)', p_from_unit, p_to_unit, p_tenant, p_product USING ERRCODE = '22023';\n END IF;\n RETURN p_qty * v_f1 * v_f2;\nEND $$;\n\nCREATE FUNCTION public.inventory_open_count_session(p_stock_location_id uuid, p_category_id uuid DEFAULT NULL::uuid, p_reference text DEFAULT NULL::text, p_blind boolean DEFAULT true, p_notes text DEFAULT NULL::text) RETURNS uuid\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO 'public'\n AS $$\nDECLARE\n v_tenant uuid;\n v_session_id uuid;\nBEGIN\n SELECT tenant_id INTO v_tenant\n FROM plg_inventory_stock_locations WHERE id = p_stock_location_id;\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory_open_count_session: unknown stock location %', p_stock_location_id;\n END IF;\n IF v_tenant NOT IN (SELECT public.user_tenant_ids()) THEN\n RAISE EXCEPTION 'inventory_open_count_session: not a member of this tenant';\n END IF;\n\n INSERT INTO plg_inventory_count_sessions (\n tenant_id, reference, status, stock_location_id, category_id, blind, notes, opened_by\n ) VALUES (\n v_tenant, NULLIF(btrim(COALESCE(p_reference, '')), ''), 'open',\n p_stock_location_id, p_category_id, COALESCE(p_blind, true),\n NULLIF(btrim(COALESCE(p_notes, '')), ''), auth.uid()\n )\n RETURNING id INTO v_session_id;\n\n -- Assets are patrimony, not stock, so they are never on a count sheet.\n INSERT INTO plg_inventory_count_items (\n tenant_id, session_id, product_id, system_quantity, unit_cost\n )\n SELECT\n v_tenant, v_session_id, p.id,\n COALESCE(pos.quantity, 0),\n COALESCE(pos.unit_cost, p.cost, 0)\n FROM products p\n LEFT JOIN plg_inventory_product_details d ON d.product_id = p.id\n LEFT JOIN LATERAL (\n SELECT sum(sp.quantity) AS quantity, max(sp.unit_cost) AS unit_cost\n FROM plg_inventory_stock_positions sp\n WHERE sp.tenant_id = v_tenant\n AND sp.product_id = p.id\n AND sp.stock_location_id = p_stock_location_id\n ) pos ON true\n WHERE p.tenant_id = v_tenant\n AND p.is_active = true\n AND COALESCE(p.metadata->>'productType', 'sale') <> 'asset'\n AND (p_category_id IS NULL OR d.category_id = p_category_id);\n\n RETURN v_session_id;\nEND;\n$$;\n\nCREATE FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb DEFAULT '{}'::jsonb, p_idempotency_key text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'receive:' || gen_random_uuid()::text);\n v_op record;\n v_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_doc jsonb := coalesce(p_document, '{}'::jsonb);\n v_supplier uuid;\n v_date date;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n v_unit := app.inventory_authorize_location(v_tenant, p_location, 'inventory.create');\n BEGIN\n v_supplier := (v_doc->>'supplier_id')::uuid;\n v_date := (v_doc->>'date')::date;\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid document: %', SQLERRM USING ERRCODE = '22023';\n END;\n IF v_supplier IS NOT NULL AND NOT EXISTS (SELECT 1 FROM public.people s WHERE s.id = v_supplier AND s.tenant_id = v_tenant) THEN\n RAISE EXCEPTION 'inventory: supplier % not found in this tenant', v_supplier USING ERRCODE = '22023';\n END IF;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'receive', v_key,\n jsonb_build_object('location', p_location, 'lines', p_lines, 'document', v_doc));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n supplier_id, document_type, document_number, notes, movement_date, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'in', v_ln.quantity, coalesce(v_ln.unit_cost, 0), p_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n v_supplier, coalesce(v_doc->>'type', 'manual'), v_doc->>'ref', coalesce(v_ln.notes, v_doc->>'notes'), coalesce(v_date, current_date),\n v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'receive', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'receive', 'idempotency_key', v_key,\n 'location_id', p_location, 'unit_id', v_unit, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('location_id', p_location, 'unit_id', v_unit, 'lines', v_no, 'document_type', coalesce(v_doc->>'type', 'manual')));\nEND $$;\n\nCREATE FUNCTION public.inventory_register_product_image(p_product uuid, p_storage_path text, p_public_url text, p_file_name text, p_file_size integer, p_mime_type text) RETURNS uuid\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_document uuid;\n v_prefix text;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission_anywhere('inventory.edit') THEN\n RAISE EXCEPTION 'inventory: inventory.edit required to register a product image' USING ERRCODE = '42501';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.products p\n WHERE p.id = p_product AND p.tenant_id = v_tenant AND p.kind = 'good'\n ) THEN\n RAISE EXCEPTION 'inventory: product not found in this tenant' USING ERRCODE = '22023';\n END IF;\n\n v_prefix := v_tenant::text || '/products/' || p_product::text || '/';\n IF nullif(btrim(p_storage_path), '') IS NULL OR p_storage_path NOT LIKE v_prefix || '%' THEN\n RAISE EXCEPTION 'inventory: product image path is outside its tenant/product prefix' USING ERRCODE = '22023';\n END IF;\n IF nullif(btrim(p_public_url), '') IS NULL THEN\n RAISE EXCEPTION 'inventory: product image URL is required' USING ERRCODE = '22023';\n END IF;\n IF p_file_size IS NULL OR p_file_size <= 0 OR p_file_size > 8388608 THEN\n RAISE EXCEPTION 'inventory: product image must be between 1 byte and 8 MB' USING ERRCODE = '22023';\n END IF;\n IF coalesce(p_mime_type, '') <> ALL (ARRAY['image/jpeg','image/png','image/webp','image/heic','image/heif']) THEN\n RAISE EXCEPTION 'inventory: unsupported product image type' USING ERRCODE = '22023';\n END IF;\n\n UPDATE public.documents\n SET is_active = false, status = 'archived', updated_at = now()\n WHERE tenant_id = v_tenant\n AND kind = 'inventory_product_image'\n AND subject_type = 'product'\n AND subject_id = p_product\n AND is_active;\n\n INSERT INTO public.documents (\n tenant_id, kind, title, status, file_url, file_name, file_size, mime_type,\n storage_provider, storage_bucket, storage_path, subject_type, subject_id,\n metadata, created_by, updated_by\n ) VALUES (\n v_tenant, 'inventory_product_image', coalesce(nullif(btrim(p_file_name), ''), 'Product image'),\n 'active', p_public_url, p_file_name, p_file_size, p_mime_type,\n 'supabase', 'inventory-images', p_storage_path, 'product', p_product,\n jsonb_build_object('plugin', 'inventory'), auth.uid(), auth.uid()\n ) RETURNING id INTO v_document;\n\n -- Compatibility projection for readers that have not moved to documents yet.\n UPDATE public.products\n SET image_url = p_public_url, updated_at = now()\n WHERE id = p_product AND tenant_id = v_tenant;\n\n INSERT INTO public.audit_logs (tenant_id, user_id, action, entity_type, entity_id, metadata)\n VALUES (\n v_tenant, auth.uid(), 'inventory.productImage.registered', 'document', v_document::text,\n jsonb_build_object('product_id', p_product, 'storage_path', p_storage_path)\n );\n\n RETURN v_document;\nEND $$;\n\nCREATE FUNCTION public.inventory_reserve(p_source_type text, p_source_id uuid, p_lines jsonb, p_idempotency_key text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_source_type text := nullif(btrim(p_source_type), '');\n v_key text;\n v_op record;\n v_line jsonb;\n v_ln record;\n v_loc uuid;\n v_unit uuid;\n v_no integer := 0;\n v_id uuid;\n v_avail numeric;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n IF v_source_type IS NULL OR p_source_id IS NULL THEN\n RAISE EXCEPTION 'inventory: a reservation needs source_type and source_id' USING ERRCODE = '22023';\n END IF;\n v_key := coalesce(nullif(btrim(p_idempotency_key), ''), v_source_type || ':' || p_source_id::text);\n PERFORM app.inventory_check_lines(p_lines);\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'reserve', v_key,\n jsonb_build_object('source_type', v_source_type, 'source_id', p_source_id, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n BEGIN\n v_loc := coalesce((v_line->>'location_id')::uuid, (v_line->>'stock_location_id')::uuid);\n EXCEPTION WHEN OTHERS THEN\n RAISE EXCEPTION 'inventory: invalid line %: %', v_line, SQLERRM USING ERRCODE = '22023';\n END;\n v_unit := app.inventory_authorize_location(v_tenant, v_loc, 'inventory.create');\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n v_avail := app.inventory_available(v_tenant, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date);\n IF v_avail < v_ln.quantity THEN\n RAISE EXCEPTION 'inventory: insufficient stock to reserve product % at location % (% available, % requested)',\n v_ln.product_id, v_loc, v_avail, v_ln.quantity USING ERRCODE = '23514';\n END IF;\n INSERT INTO public.plg_inventory_reservations\n (tenant_id, unit_id, idempotency_key, line_no, source_type, source_id, product_id, stock_location_id, batch_number, expiration_date,\n quantity, measurement_unit_id, status, metadata)\n VALUES\n (v_tenant, v_unit, v_key, v_no, v_source_type, p_source_id, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date,\n v_ln.quantity, v_ln.measurement_unit_id, 'reserved', v_ln.declared)\n RETURNING id INTO v_id;\n v_reservations := v_reservations || app.inventory_reservation_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, v_loc, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'reserve', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'reserve', 'idempotency_key', v_key,\n 'source_type', v_source_type, 'source_id', p_source_id, 'status', 'reserved',\n 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('source_type', v_source_type, 'source_id', p_source_id, 'lines', v_no));\nEND $$;\n\nCREATE FUNCTION public.inventory_reverse(p_idempotency_key text, p_reason text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := nullif(btrim(p_idempotency_key), '');\n v_reason text := nullif(btrim(p_reason), '');\n v_op record;\n r record;\n v_id uuid;\n v_n integer := 0;\n v_no integer := 0;\n v_avail numeric;\n v_movements jsonb := '[]'::jsonb;\n v_reservations jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_had boolean := false;\nBEGIN\n IF v_key IS NULL THEN\n RAISE EXCEPTION 'inventory: idempotency_key is required' USING ERRCODE = '22023';\n END IF;\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: a reversal needs a reason' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key)\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.kind <> 'reverse') THEN\n RAISE EXCEPTION 'inventory: nothing to reverse under key % in this tenant', v_key USING ERRCODE = '22023';\n END IF;\n -- authorization first: every unit touched by the key\n FOR r IN SELECT DISTINCT stock_location_id AS loc FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key\n UNION SELECT DISTINCT source_location_id FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key\n UNION SELECT DISTINCT destination_location_id FROM public.plg_inventory_stock_movements m WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.destination_location_id IS NOT NULL LOOP\n PERFORM app.inventory_authorize_location(v_tenant, r.loc, 'inventory.edit');\n END LOOP;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'reverse', v_key, jsonb_build_object('idempotency_key', v_key, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n -- 1. reservations under the key\n FOR r IN SELECT * FROM public.plg_inventory_reservations x\n WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no FOR UPDATE LOOP\n v_had := true;\n IF r.status = 'reserved' THEN\n UPDATE public.plg_inventory_reservations x SET status = 'reversed', reversed_at = now(), reversed_by = auth.uid(), reason = v_reason\n WHERE x.id = r.id AND x.status = 'reserved';\n v_n := v_n + 1;\n ELSIF r.status = 'confirmed' AND r.movement_id IS NOT NULL THEN\n SELECT m.* INTO STRICT r FROM public.plg_inventory_stock_movements m WHERE m.id = r.movement_id;\n v_no := v_no + 1;\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, reason, source_item_type, source_item_id, reverses_movement_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'reverse', -r.quantity, r.unit_cost, r.source_location_id, r.destination_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'reversal', r.document_number, v_reason, r.source_item_type, r.source_item_id, r.id, 'reverse:' || v_key, v_no, v_op.op_id,\n jsonb_build_object('reversed_movement_id', r.id))\n RETURNING id INTO v_id;\n UPDATE public.plg_inventory_reservations x\n SET status = 'reversed', reversed_at = now(), reversed_by = auth.uid(), reason = v_reason, reversal_movement_id = v_id\n WHERE x.movement_id = r.id AND x.status = 'confirmed';\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_n := v_n + 1;\n END IF;\n END LOOP;\n FOR r IN SELECT * FROM public.plg_inventory_reservations x WHERE x.tenant_id = v_tenant AND x.idempotency_key = v_key ORDER BY x.line_no LOOP\n v_reservations := v_reservations || app.inventory_reservation_json(r.id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.stock_location_id, r.batch_number, r.expiration_date);\n END LOOP;\n\n -- 2. plain movements under the key (receive / transfer / adjust), not yet reversed\n IF NOT v_had THEN\n FOR r IN SELECT m.* FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = v_tenant AND m.idempotency_key = v_key AND m.kind <> 'reverse'\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements x WHERE x.reverses_movement_id = m.id)\n ORDER BY m.line_no, m.created_at LOOP\n -- undoing an 'in' or a transfer's arrival must not go below what is still available\n IF r.quantity > 0 THEN\n v_avail := app.inventory_available(v_tenant, r.product_id, r.source_location_id, r.batch_number, r.expiration_date);\n IF v_avail < r.quantity THEN\n RAISE EXCEPTION 'inventory: cannot reverse movement % — only % of % still available at the source location', r.id, v_avail, r.quantity USING ERRCODE = '23514';\n END IF;\n END IF;\n IF r.destination_location_id IS NOT NULL AND r.quantity < 0 THEN\n v_avail := app.inventory_available(v_tenant, r.product_id, r.destination_location_id, r.batch_number, r.expiration_date);\n IF v_avail < -r.quantity THEN\n RAISE EXCEPTION 'inventory: cannot reverse transfer % — only % of % still available at the destination', r.id, v_avail, -r.quantity USING ERRCODE = '23514';\n END IF;\n END IF;\n v_no := v_no + 1;\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, document_number, reason, supplier_id, source_item_type, source_item_id, reverses_movement_id, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, r.product_id, 'reverse', -r.quantity, r.unit_cost, r.source_location_id, r.destination_location_id, r.batch_number, r.expiration_date, r.measurement_unit_id,\n 'reversal', r.document_number, v_reason, r.supplier_id, r.source_item_type, r.source_item_id, r.id, 'reverse:' || v_key, v_no, v_op.op_id,\n jsonb_build_object('reversed_movement_id', r.id, 'reversed_kind', r.kind))\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.source_location_id, r.batch_number, r.expiration_date);\n IF r.destination_location_id IS NOT NULL THEN\n v_positions := v_positions || app.inventory_position_json(v_tenant, r.product_id, r.destination_location_id, r.batch_number, r.expiration_date);\n END IF;\n v_n := v_n + 1;\n END LOOP;\n END IF;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'reverse', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'reverse', 'idempotency_key', v_key, 'reason', v_reason,\n 'status', 'reversed', 'reversed_lines', v_n,\n 'movements', v_movements, 'reservations', v_reservations, 'positions', v_positions),\n jsonb_build_object('reason', v_reason, 'reversed_lines', v_n));\nEND $$;\n\nCREATE FUNCTION public.inventory_seed_measurement_units() RETURNS integer\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE v_tenant uuid := app.current_tenant_id();\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'inventory: no tenant in session' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('inventory.manage') THEN\n RAISE EXCEPTION 'inventory: inventory.manage required' USING ERRCODE = '42501';\n END IF;\n RETURN public.inventory_seed_measurement_units(v_tenant);\nEND $$;\n\nCREATE FUNCTION public.inventory_seed_measurement_units(p_tenant uuid) RETURNS integer\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_n integer := 0;\n v_ins integer;\n v_kg uuid; v_g uuid; v_l uuid; v_ml uuid;\nBEGIN\n IF p_tenant IS NULL THEN RETURN 0; END IF;\n WITH ins AS (\n INSERT INTO public.plg_inventory_measurement_units (tenant_id, name, abbreviation, code, kind, is_base, is_active)\n SELECT p_tenant, s.name, s.abbr, s.code, s.kind, s.is_base, true\n FROM (VALUES\n ('Unidade', 'un', 'un', 'unit', true),\n ('Caixa', 'cx', 'cx', 'unit', false),\n ('Quilograma', 'kg', 'kg', 'mass', false),\n ('Grama', 'g', 'g', 'mass', true),\n ('Litro', 'L', 'l', 'volume', false),\n ('Mililitro', 'mL', 'ml', 'volume', true)\n ) AS s(name, abbr, code, kind, is_base)\n WHERE NOT EXISTS (SELECT 1 FROM public.plg_inventory_measurement_units u WHERE u.tenant_id = p_tenant AND lower(u.code) = s.code)\n RETURNING 1\n ) SELECT count(*) INTO v_ins FROM ins;\n v_n := v_n + coalesce(v_ins, 0);\n\n SELECT id INTO v_kg FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'kg';\n SELECT id INTO v_g FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'g';\n SELECT id INTO v_l FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'l';\n SELECT id INTO v_ml FROM public.plg_inventory_measurement_units WHERE tenant_id = p_tenant AND lower(code) = 'ml';\n WITH ins AS (\n INSERT INTO public.plg_inventory_unit_conversions (tenant_id, from_unit_id, to_unit_id, factor)\n SELECT p_tenant, c.f, c.t, c.factor\n FROM (VALUES (v_kg, v_g, 1000::numeric), (v_l, v_ml, 1000::numeric)) AS c(f, t, factor)\n WHERE c.f IS NOT NULL AND c.t IS NOT NULL\n AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_unit_conversions x\n WHERE x.tenant_id = p_tenant AND x.from_unit_id = c.f AND x.to_unit_id = c.t AND x.product_id IS NULL)\n RETURNING 1\n ) SELECT count(*) INTO v_ins FROM ins;\n RETURN v_n + coalesce(v_ins, 0);\nEND $$;\n\nCREATE FUNCTION public.inventory_transfer(p_from_location uuid, p_to_location uuid, p_lines jsonb, p_idempotency_key text DEFAULT NULL::text) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_key text := coalesce(nullif(btrim(p_idempotency_key), ''), 'transfer:' || gen_random_uuid()::text);\n v_op record;\n v_from_unit uuid; v_to_unit uuid;\n v_line jsonb;\n v_ln record;\n v_no integer := 0;\n v_id uuid;\n v_avail numeric;\n v_cost numeric;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n IF p_from_location IS NULL OR p_to_location IS NULL OR p_from_location = p_to_location THEN\n RAISE EXCEPTION 'inventory: a transfer needs two different stock locations' USING ERRCODE = '22023';\n END IF;\n v_from_unit := app.inventory_authorize_location(v_tenant, p_from_location, 'inventory.edit');\n v_to_unit := app.inventory_authorize_location(v_tenant, p_to_location, 'inventory.create');\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(v_tenant, 'transfer', v_key,\n jsonb_build_object('from_location', p_from_location, 'to_location', p_to_location, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN RETURN v_op.existing; END IF;\n\n FOR v_line IN SELECT * FROM jsonb_array_elements(p_lines) LOOP\n v_no := v_no + 1;\n SELECT * INTO v_ln FROM app.inventory_parse_line(v_tenant, v_line, 'positive');\n v_avail := app.inventory_available(v_tenant, v_ln.product_id, p_from_location, v_ln.batch_number, v_ln.expiration_date);\n IF v_avail < v_ln.quantity THEN\n RAISE EXCEPTION 'inventory: insufficient stock to transfer product % from location % (% available, % requested)',\n v_ln.product_id, p_from_location, v_avail, v_ln.quantity USING ERRCODE = '23514';\n END IF;\n SELECT p.unit_cost INTO v_cost FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_ln.product_id AND p.stock_location_id = p_from_location\n AND coalesce(p.batch_number, '') = coalesce(v_ln.batch_number, '')\n AND coalesce(p.expiration_date, 'infinity'::date) = coalesce(v_ln.expiration_date, 'infinity'::date);\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id, destination_location_id, batch_number, expiration_date, measurement_unit_id,\n document_type, notes, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, 'transfer', -v_ln.quantity, coalesce(v_cost, 0), p_from_location, p_to_location, v_ln.batch_number, v_ln.expiration_date, v_ln.measurement_unit_id,\n 'transfer', v_ln.notes, v_key, v_no, v_op.op_id, v_ln.declared)\n RETURNING id INTO v_id;\n v_movements := v_movements || app.inventory_movement_json(v_id);\n v_positions := v_positions || app.inventory_position_json(v_tenant, v_ln.product_id, p_from_location, v_ln.batch_number, v_ln.expiration_date)\n || app.inventory_position_json(v_tenant, v_ln.product_id, p_to_location, v_ln.batch_number, v_ln.expiration_date);\n END LOOP;\n\n RETURN app.inventory_finish_operation(v_tenant, v_op.op_id, 'transfer', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'transfer', 'idempotency_key', v_key,\n 'from_location_id', p_from_location, 'to_location_id', p_to_location,\n 'from_unit_id', v_from_unit, 'to_unit_id', v_to_unit, 'movements', v_movements, 'positions', v_positions),\n jsonb_build_object('from_location_id', p_from_location, 'to_location_id', p_to_location, 'lines', v_no));\nEND $$;\n\nCREATE FUNCTION public.plg_inventory_on_fulfillment_completed(p_event jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := nullif(p_event ->> 'tenant_id', '')::uuid;\n v_ful_id uuid := nullif(p_event ->> 'subject_id', '')::uuid;\n v_actor uuid := nullif(p_event ->> 'actor_id', '')::uuid;\n v_ful public.fulfillments%ROWTYPE;\n v_line record;\n v_result jsonb;\n v_results jsonb := '[]'::jsonb;\n v_count integer := 0;\nBEGIN\n IF v_tenant IS NULL OR v_ful_id IS NULL THEN\n RAISE EXCEPTION 'fulfillment.completed carried no tenant or subject id' USING ERRCODE = '22023';\n END IF;\n IF public.app_product_stock_owner(v_tenant) <> 'inventory' THEN\n RETURN jsonb_build_object('skipped', 'stock owner is not inventory for this tenant');\n END IF;\n\n SELECT * INTO v_ful FROM public.fulfillments f WHERE f.id = v_ful_id AND f.tenant_id = v_tenant;\n IF v_ful.id IS NULL THEN\n RETURN jsonb_build_object('skipped', 'fulfillment not found');\n END IF;\n IF v_ful.status NOT IN ('delivered', 'completed') THEN\n RETURN jsonb_build_object('skipped', 'delivery is no longer completed', 'current_status', v_ful.status);\n END IF;\n\n FOR v_line IN\n SELECT i.id, i.product_id, i.quantity\n FROM public.items i\n JOIN public.products p ON p.id = i.product_id AND p.tenant_id = v_tenant\n WHERE i.fulfillment_id = v_ful.id AND i.tenant_id = v_tenant\n AND i.product_id IS NOT NULL AND coalesce(i.quantity, 0) > 0\n AND p.kind = 'good'\n ORDER BY i.sort_order, i.created_at, i.id\n LOOP\n -- The DELIVERY line is the idempotency source, not the order line: two\n -- deliveries of the same order line are two movements, and re-running this\n -- handler is none.\n v_result := app.inventory_consume_order_item(\n v_tenant, v_ful.order_id, v_line.id, v_ful.unit_id,\n v_line.product_id, v_line.quantity, v_actor);\n v_results := v_results || v_result;\n v_count := v_count + 1;\n END LOOP;\n\n RETURN jsonb_build_object('fulfillment_id', v_ful.id, 'order_id', v_ful.order_id,\n 'consumed_items', v_count, 'results', v_results);\nEND $$;\n\nCREATE FUNCTION public.plg_inventory_on_order_completed(p_event jsonb) RETURNS jsonb\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE\n v_tenant uuid := nullif(p_event ->> 'tenant_id', '')::uuid;\n v_order uuid := nullif(p_event ->> 'subject_id', '')::uuid;\n v_actor uuid := nullif(p_event ->> 'actor_id', '')::uuid;\n v_order_row record;\n v_item record;\n v_result jsonb;\n v_results jsonb := '[]'::jsonb;\n v_count integer := 0;\n v_delivered integer := 0;\nBEGIN\n IF v_tenant IS NULL OR v_order IS NULL THEN\n RAISE EXCEPTION 'order.completed carried no tenant or subject id' USING ERRCODE = '22023';\n END IF;\n IF public.app_product_stock_owner(v_tenant) <> 'inventory' THEN\n RETURN jsonb_build_object('skipped', 'stock owner is not inventory for this tenant');\n END IF;\n\n SELECT o.status, o.unit_id INTO v_order_row\n FROM public.orders o WHERE o.id = v_order AND o.tenant_id = v_tenant;\n IF v_order_row.status IS NULL THEN\n RAISE EXCEPTION 'inventory: order % was not found for tenant %', v_order, v_tenant\n USING ERRCODE = '22023';\n END IF;\n IF v_order_row.status <> 'completed' THEN\n RETURN jsonb_build_object('skipped', 'order is no longer completed',\n 'order_id', v_order, 'current_status', v_order_row.status);\n END IF;\n\n FOR v_item IN\n SELECT oi.id, oi.product_id, oi.quantity\n FROM public.items oi\n JOIN public.products p ON p.id = oi.product_id AND p.tenant_id = v_tenant\n WHERE oi.order_id = v_order AND oi.tenant_id = v_tenant\n AND oi.cancelled_at IS NULL\n AND oi.product_id IS NOT NULL AND coalesce(oi.quantity, 0) > 0\n AND p.kind = 'good'\n ORDER BY oi.sort_order, oi.created_at, oi.id\n LOOP\n -- The delivery is the movement where a delivery exists.\n IF EXISTS (\n SELECT 1\n FROM public.item_associations a\n JOIN public.items t ON t.id = a.to_item_id\n WHERE a.from_item_id = v_item.id AND t.fulfillment_id IS NOT NULL\n ) THEN\n v_delivered := v_delivered + 1;\n CONTINUE;\n END IF;\n\n v_result := app.inventory_consume_order_item(\n v_tenant, v_order, v_item.id, v_order_row.unit_id,\n v_item.product_id, v_item.quantity, v_actor\n );\n v_results := v_results || v_result;\n v_count := v_count + 1;\n END LOOP;\n\n RETURN jsonb_build_object('order_id', v_order, 'consumed_items', v_count,\n 'delivered_elsewhere', v_delivered, 'results', v_results);\nEND $$;\n\nCREATE FUNCTION public.trg_fulfillments_emit() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nBEGIN\n IF NEW.status NOT IN ('delivered', 'completed') THEN RETURN NULL; END IF;\n IF TG_OP = 'UPDATE' AND OLD.status IN ('delivered', 'completed') THEN RETURN NULL; END IF;\n\n PERFORM public.plg_emit_event(\n 'fulfillment.completed',\n jsonb_build_object(\n 'fulfillment_id', NEW.id,\n 'order_id', NEW.order_id,\n 'kind', NEW.kind,\n 'unit_id', NEW.unit_id,\n 'occurred_at', coalesce(NEW.occurred_at, now())\n ),\n 'fulfillment', NEW.id::text, NEW.tenant_id, NULL);\n RETURN NULL;\nEND $$;\n\nCREATE FUNCTION public.trg_plg_inventory_fulfillment_items_inherit() RETURNS trigger\n LANGUAGE plpgsql SECURITY DEFINER\n SET search_path TO ''\n AS $$\nDECLARE v_tenant uuid; v_unit uuid;\nBEGIN\n SELECT i.tenant_id, i.unit_id INTO v_tenant, v_unit FROM public.items i WHERE i.id = NEW.item_id;\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'plg_inventory_fulfillment_items: line % not found', NEW.item_id USING ERRCODE = '23503';\n END IF;\n NEW.tenant_id := v_tenant;\n IF NEW.unit_id IS NULL THEN NEW.unit_id := v_unit; END IF;\n RETURN NEW;\nEND $$;\n\n\n-- ── constraint ──────────────────────────────────────────────────────────\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items\n ADD CONSTRAINT plg_inventory_fulfillment_items_pkey PRIMARY KEY (item_id);\n\nALTER TABLE ONLY public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_operations\n ADD CONSTRAINT plg_inventory_operations_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_operations\n ADD CONSTRAINT plg_inventory_operations_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_pkey PRIMARY KEY (product_id);\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_recipe_groups\n ADD CONSTRAINT plg_inventory_recipe_groups_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_tenant_id_id_key UNIQUE (tenant_id, id);\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_pkey PRIMARY KEY (id);\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_tenant_id_id_key UNIQUE (tenant_id, id);\n\n\n-- ── view ────────────────────────────────────────────────────────────────\n\nCREATE VIEW public.v_inventory_balances WITH (security_invoker='true') AS\n SELECT p.id,\n p.tenant_id,\n p.unit_id,\n p.product_id,\n pl.name AS product_name,\n pl.sku AS product_sku,\n p.stock_location_id,\n l.name AS location_name,\n p.batch_number,\n p.expiration_date,\n p.quantity,\n COALESCE(r.reserved, (0)::numeric) AS reserved_quantity,\n (p.quantity - COALESCE(r.reserved, (0)::numeric)) AS available_quantity,\n p.unit_cost,\n (p.quantity * p.unit_cost) AS total_value,\n p.measurement_unit_id,\n mu.code AS measurement_unit_code,\n p.created_at,\n p.updated_at\n FROM ((((public.plg_inventory_stock_positions p\n LEFT JOIN public.plg_inventory_stock_locations l ON ((l.id = p.stock_location_id)))\n LEFT JOIN public.plg_inventory_measurement_units mu ON ((mu.id = p.measurement_unit_id)))\n LEFT JOIN LATERAL app.inventory_product_label(p.product_id) pl(name, sku) ON (true))\n LEFT JOIN LATERAL ( SELECT sum(x.quantity) AS reserved\n FROM public.plg_inventory_reservations x\n WHERE ((x.tenant_id = p.tenant_id) AND (x.product_id = p.product_id) AND (x.stock_location_id = p.stock_location_id) AND (COALESCE(x.batch_number, ''::text) = COALESCE(p.batch_number, ''::text)) AND (COALESCE(x.expiration_date, 'infinity'::date) = COALESCE(p.expiration_date, 'infinity'::date)) AND (x.status = 'reserved'::text))) r ON (true));\n\nCREATE VIEW public.v_inventory_low_stock WITH (security_invoker='true') AS\n WITH per_unit AS (\n SELECT b.tenant_id,\n b.product_id,\n b.unit_id,\n sum(b.quantity) AS on_hand,\n sum(b.available_quantity) AS available_quantity\n FROM public.v_inventory_balances b\n GROUP BY b.tenant_id, b.product_id, b.unit_id\n ), tenant_wide AS (\n SELECT b.tenant_id,\n b.product_id,\n NULL::uuid AS unit_id,\n sum(b.quantity) AS on_hand,\n sum(b.available_quantity) AS available_quantity\n FROM public.v_inventory_balances b\n GROUP BY b.tenant_id, b.product_id\n ), scopes AS (\n SELECT per_unit.tenant_id,\n per_unit.product_id,\n per_unit.unit_id,\n per_unit.on_hand,\n per_unit.available_quantity\n FROM per_unit\n UNION ALL\n SELECT tenant_wide.tenant_id,\n tenant_wide.product_id,\n tenant_wide.unit_id,\n tenant_wide.on_hand,\n tenant_wide.available_quantity\n FROM tenant_wide\n ), settings AS (\n SELECT s_1.tenant_id,\n s_1.product_id,\n s_1.unit_id,\n s_1.min_quantity,\n s_1.max_quantity\n FROM public.plg_inventory_product_settings s_1\n )\n SELECT s.tenant_id,\n s.product_id,\n pl.name AS product_name,\n pl.sku AS product_sku,\n s.unit_id,\n COALESCE(sc.on_hand, (0)::numeric) AS on_hand,\n COALESCE(sc.available_quantity, (0)::numeric) AS available_quantity,\n s.min_quantity,\n s.max_quantity,\n (s.min_quantity - COALESCE(sc.on_hand, (0)::numeric)) AS shortfall\n FROM ((settings s\n LEFT JOIN scopes sc ON (((sc.tenant_id = s.tenant_id) AND (sc.product_id = s.product_id) AND (NOT (sc.unit_id IS DISTINCT FROM s.unit_id)))))\n LEFT JOIN LATERAL app.inventory_product_label(s.product_id) pl(name, sku) ON (true))\n WHERE ((s.min_quantity > (0)::numeric) AND (COALESCE(sc.on_hand, (0)::numeric) <= s.min_quantity));\n\nCREATE VIEW public.v_inventory_movements WITH (security_invoker='true') AS\n SELECT m.id,\n m.tenant_id,\n m.unit_id,\n m.product_id,\n pl.name AS product_name,\n pl.sku AS product_sku,\n m.kind,\n CASE m.kind\n WHEN 'in'::text THEN 'entry'::text\n WHEN 'out'::text THEN\n CASE\n WHEN ((m.reason ~~* 'loss%'::text) OR (m.document_type = 'loss'::text)) THEN 'loss'::text\n ELSE 'exit'::text\n END\n WHEN 'transfer'::text THEN 'transfer'::text\n WHEN 'adjust'::text THEN 'adjustment'::text\n WHEN 'reverse'::text THEN 'adjustment'::text\n ELSE NULL::text\n END AS movement_type,\n m.quantity,\n abs(m.quantity) AS abs_quantity,\n m.unit_cost,\n m.total_cost,\n m.source_location_id,\n sl.name AS source_location_name,\n m.destination_location_id,\n dl.name AS destination_location_name,\n m.batch_number,\n m.expiration_date,\n m.measurement_unit_id,\n mu.code AS measurement_unit_code,\n m.supplier_id,\n sp.name AS supplier_name,\n m.document_type,\n m.document_number,\n m.reason,\n m.notes,\n m.movement_date,\n m.user_id,\n m.reverses_movement_id,\n m.idempotency_key,\n m.line_no,\n m.operation_id,\n m.source_item_type,\n m.source_item_id,\n m.metadata,\n m.created_at\n FROM (((((public.plg_inventory_stock_movements m\n LEFT JOIN LATERAL app.inventory_product_label(m.product_id) pl(name, sku) ON (true))\n LEFT JOIN public.plg_inventory_stock_locations sl ON ((sl.id = m.source_location_id)))\n LEFT JOIN public.plg_inventory_stock_locations dl ON ((dl.id = m.destination_location_id)))\n LEFT JOIN public.plg_inventory_measurement_units mu ON ((mu.id = m.measurement_unit_id)))\n LEFT JOIN public.people sp ON ((sp.id = m.supplier_id)));\n\nCREATE VIEW public.v_inventory_product_totals WITH (security_invoker='true') AS\n SELECT tenant_id,\n product_id,\n max(product_name) AS product_name,\n max(product_sku) AS product_sku,\n sum(quantity) AS on_hand,\n sum(reserved_quantity) AS reserved_quantity,\n sum(available_quantity) AS available_quantity,\n CASE\n WHEN (sum(quantity) > (0)::numeric) THEN round((sum((quantity * unit_cost)) / sum(quantity)), 4)\n ELSE max(unit_cost)\n END AS avg_unit_cost,\n sum(total_value) AS total_value,\n (count(DISTINCT stock_location_id))::integer AS location_count,\n (count(*))::integer AS position_count,\n min(expiration_date) AS next_expiration,\n max(updated_at) AS updated_at\n FROM public.v_inventory_balances b\n GROUP BY tenant_id, product_id;\n\nCREATE VIEW public.v_inventory_products WITH (security_invoker='true') AS\n SELECT p.id,\n p.tenant_id,\n p.category_id,\n p.name,\n p.description,\n p.sku,\n p.price,\n p.cost,\n p.currency,\n p.unit,\n p.image_url,\n p.status,\n p.is_active,\n p.tags,\n p.metadata,\n p.created_at,\n p.updated_at,\n p.created_by,\n p.custom_fields,\n p.unit_id,\n p.owner_id,\n p.kind,\n p.subkind,\n p.duration_minutes,\n p.service_kind,\n COALESCE(t.on_hand, (0)::numeric) AS stock,\n COALESCE(t.available_quantity, (0)::numeric) AS available,\n COALESCE(t.reserved_quantity, (0)::numeric) AS reserved,\n COALESCE(s.min_quantity, (0)::numeric) AS min_stock,\n s.max_quantity AS max_stock,\n t.location_count,\n t.next_expiration\n FROM ((public.products p\n LEFT JOIN public.v_inventory_product_totals t ON (((t.tenant_id = p.tenant_id) AND (t.product_id = p.id))))\n LEFT JOIN public.plg_inventory_product_settings s ON (((s.tenant_id = p.tenant_id) AND (s.product_id = p.id) AND (s.unit_id IS NULL))));\n\nCREATE VIEW public.v_stock_movements WITH (security_invoker='true') AS\n SELECT sm.id,\n sm.tenant_id,\n sm.product_id,\n sm.quantity,\n sm.kind AS movement_type,\n sm.unit_cost,\n sm.total_cost,\n sm.source_location_id AS stock_location_id,\n sm.destination_location_id,\n sm.supplier_id,\n sm.document_number,\n sm.reason,\n sm.notes,\n sm.movement_date,\n sm.user_id,\n sm.batch_number,\n sm.expiration_date,\n sm.metadata,\n sm.created_at,\n p.name AS product_name,\n p.sku AS product_sku,\n sl.name AS stock_location_name,\n dl.name AS destination_location_name\n FROM (((public.plg_inventory_stock_movements sm\n LEFT JOIN public.products p ON ((p.id = sm.product_id)))\n LEFT JOIN public.plg_inventory_stock_locations sl ON ((sl.id = sm.source_location_id)))\n LEFT JOIN public.plg_inventory_stock_locations dl ON ((dl.id = sm.destination_location_id)));\n\n\n-- ── index ───────────────────────────────────────────────────────────────\n\nCREATE INDEX idx_plg_inventory_count_items_tenant ON public.plg_inventory_count_items USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_count_sessions_status ON public.plg_inventory_count_sessions USING btree (tenant_id, status);\n\nCREATE INDEX idx_plg_inventory_count_sessions_tenant ON public.plg_inventory_count_sessions USING btree (tenant_id, opened_at DESC);\n\nCREATE INDEX idx_plg_inventory_measurement_units_tenant ON public.plg_inventory_measurement_units USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_product_categories_tenant ON public.plg_inventory_product_categories USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_product_details_category ON public.plg_inventory_product_details USING btree (category_id);\n\nCREATE INDEX idx_plg_inventory_product_details_supplier ON public.plg_inventory_product_details USING btree (supplier_id);\n\nCREATE INDEX idx_plg_inventory_product_details_tenant ON public.plg_inventory_product_details USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_recipe_groups_recipe ON public.plg_inventory_recipe_groups USING btree (recipe_id);\n\nCREATE INDEX idx_plg_inventory_recipe_groups_tenant ON public.plg_inventory_recipe_groups USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_recipe_ingredients_group ON public.plg_inventory_recipe_ingredients USING btree (group_id);\n\nCREATE INDEX idx_plg_inventory_recipe_ingredients_recipe ON public.plg_inventory_recipe_ingredients USING btree (recipe_id);\n\nCREATE INDEX idx_plg_inventory_recipe_ingredients_tenant ON public.plg_inventory_recipe_ingredients USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_recipes_product ON public.plg_inventory_recipes USING btree (product_id);\n\nCREATE INDEX idx_plg_inventory_recipes_tenant ON public.plg_inventory_recipes USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_stock_locations_tenant ON public.plg_inventory_stock_locations USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_stock_movements_date ON public.plg_inventory_stock_movements USING btree (tenant_id, movement_date);\n\nCREATE INDEX idx_plg_inventory_stock_movements_product ON public.plg_inventory_stock_movements USING btree (product_id);\n\nCREATE INDEX idx_plg_inventory_stock_movements_tenant ON public.plg_inventory_stock_movements USING btree (tenant_id);\n\nCREATE INDEX idx_plg_inventory_stock_positions_product ON public.plg_inventory_stock_positions USING btree (product_id);\n\nCREATE INDEX idx_plg_inventory_stock_positions_tenant ON public.plg_inventory_stock_positions USING btree (tenant_id);\n\nCREATE INDEX plg_inventory_count_items_tenant_owner_idx ON public.plg_inventory_count_items USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_count_items_tenant_unit_idx ON public.plg_inventory_count_items USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_count_sessions_tenant_owner_idx ON public.plg_inventory_count_sessions USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_count_sessions_tenant_unit_idx ON public.plg_inventory_count_sessions USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_fulfillment_items_batch_idx ON public.plg_inventory_fulfillment_items USING btree (tenant_id, batch_number) WHERE (batch_number IS NOT NULL);\n\nCREATE UNIQUE INDEX plg_inventory_measurement_units_base_key ON public.plg_inventory_measurement_units USING btree (tenant_id, kind) WHERE is_base;\n\nCREATE UNIQUE INDEX plg_inventory_measurement_units_code_key ON public.plg_inventory_measurement_units USING btree (tenant_id, lower(code)) WHERE (code IS NOT NULL);\n\nCREATE INDEX plg_inventory_measurement_units_tenant_owner_idx ON public.plg_inventory_measurement_units USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_measurement_units_tenant_unit_idx ON public.plg_inventory_measurement_units USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX plg_inventory_operations_key ON public.plg_inventory_operations USING btree (tenant_id, kind, idempotency_key);\n\nCREATE INDEX plg_inventory_operations_tenant_owner_idx ON public.plg_inventory_operations USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_operations_tenant_unit_idx ON public.plg_inventory_operations USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_product_categories_tenant_owner_idx ON public.plg_inventory_product_categories USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_product_categories_tenant_unit_idx ON public.plg_inventory_product_categories USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX plg_inventory_product_settings_product_unit_key ON public.plg_inventory_product_settings USING btree (tenant_id, product_id, COALESCE(unit_id, '00000000-0000-0000-0000-000000000000'::uuid));\n\nCREATE INDEX plg_inventory_product_settings_tenant_owner_idx ON public.plg_inventory_product_settings USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_product_settings_tenant_unit_idx ON public.plg_inventory_product_settings USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_recipes_tenant_owner_idx ON public.plg_inventory_recipes USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_recipes_tenant_unit_idx ON public.plg_inventory_recipes USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX plg_inventory_reservations_key_line ON public.plg_inventory_reservations USING btree (tenant_id, idempotency_key, line_no);\n\nCREATE UNIQUE INDEX plg_inventory_reservations_one_live_per_source_uidx ON public.plg_inventory_reservations USING btree (tenant_id, source_type, source_id, line_no) WHERE (status <> 'reversed'::text);\n\nCREATE INDEX plg_inventory_reservations_open_idx ON public.plg_inventory_reservations USING btree (tenant_id, product_id, stock_location_id) WHERE (status = 'reserved'::text);\n\nCREATE INDEX plg_inventory_reservations_source_idx ON public.plg_inventory_reservations USING btree (tenant_id, source_type, source_id);\n\nCREATE INDEX plg_inventory_reservations_tenant_owner_idx ON public.plg_inventory_reservations USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_reservations_tenant_unit_idx ON public.plg_inventory_reservations USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_stock_locations_tenant_owner_idx ON public.plg_inventory_stock_locations USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_stock_locations_tenant_unit_idx ON public.plg_inventory_stock_locations USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX plg_inventory_stock_locations_unit_name_key ON public.plg_inventory_stock_locations USING btree (tenant_id, unit_id, lower(name));\n\nCREATE INDEX plg_inventory_stock_movements_created_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, created_at DESC);\n\nCREATE INDEX plg_inventory_stock_movements_dest_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, destination_location_id, product_id) WHERE (destination_location_id IS NOT NULL);\n\nCREATE UNIQUE INDEX plg_inventory_stock_movements_idem_key ON public.plg_inventory_stock_movements USING btree (tenant_id, idempotency_key, line_no) WHERE (idempotency_key IS NOT NULL);\n\nCREATE UNIQUE INDEX plg_inventory_stock_movements_reverses_key ON public.plg_inventory_stock_movements USING btree (reverses_movement_id) WHERE (reverses_movement_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_stock_movements_source_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, source_location_id, product_id);\n\nCREATE INDEX plg_inventory_stock_movements_source_item_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, source_item_type, source_item_id) WHERE (source_item_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_stock_movements_tenant_owner_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_stock_movements_tenant_unit_idx ON public.plg_inventory_stock_movements USING btree (tenant_id, unit_id);\n\nCREATE INDEX plg_inventory_stock_positions_expiry_idx ON public.plg_inventory_stock_positions USING btree (tenant_id, expiration_date) WHERE (expiration_date IS NOT NULL);\n\nCREATE UNIQUE INDEX plg_inventory_stock_positions_identity_key ON public.plg_inventory_stock_positions USING btree (tenant_id, product_id, stock_location_id, COALESCE(batch_number, ''::text), COALESCE(expiration_date, 'infinity'::date));\n\nCREATE INDEX plg_inventory_stock_positions_location_idx ON public.plg_inventory_stock_positions USING btree (tenant_id, stock_location_id, product_id);\n\nCREATE INDEX plg_inventory_stock_positions_tenant_owner_idx ON public.plg_inventory_stock_positions USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_stock_positions_tenant_unit_idx ON public.plg_inventory_stock_positions USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX plg_inventory_unit_conversions_key ON public.plg_inventory_unit_conversions USING btree (tenant_id, from_unit_id, to_unit_id, COALESCE(product_id, '00000000-0000-0000-0000-000000000000'::uuid));\n\nCREATE INDEX plg_inventory_unit_conversions_product_idx ON public.plg_inventory_unit_conversions USING btree (tenant_id, product_id) WHERE (product_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_unit_conversions_tenant_owner_idx ON public.plg_inventory_unit_conversions USING btree (tenant_id, owner_id) WHERE (owner_id IS NOT NULL);\n\nCREATE INDEX plg_inventory_unit_conversions_tenant_unit_idx ON public.plg_inventory_unit_conversions USING btree (tenant_id, unit_id);\n\nCREATE UNIQUE INDEX uq_plg_inventory_count_items_line ON public.plg_inventory_count_items USING btree (session_id, product_id);\n\nCREATE UNIQUE INDEX uq_plg_inventory_stock_positions_slot ON public.plg_inventory_stock_positions USING btree (tenant_id, product_id, stock_location_id, batch_number, expiration_date) NULLS NOT DISTINCT;\n\n\n-- ── fk constraint ───────────────────────────────────────────────────────\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_movement_id_fkey FOREIGN KEY (movement_id) REFERENCES public.plg_inventory_stock_movements(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_session_id_fkey FOREIGN KEY (session_id) REFERENCES public.plg_inventory_count_sessions(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_count_items\n ADD CONSTRAINT plg_inventory_count_items_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_category_id_fkey FOREIGN KEY (category_id) REFERENCES public.plg_inventory_product_categories(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_stock_location_id_fkey FOREIGN KEY (stock_location_id) REFERENCES public.plg_inventory_stock_locations(id);\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items\n ADD CONSTRAINT plg_inventory_fulfillment_items_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items\n ADD CONSTRAINT plg_inventory_fulfillment_items_parent_fk FOREIGN KEY (item_id, parent_kind) REFERENCES public.items(id, parent_kind) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items\n ADD CONSTRAINT plg_inventory_fulfillment_items_stock_location_id_fkey FOREIGN KEY (stock_location_id) REFERENCES public.plg_inventory_stock_locations(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_fulfillment_items\n ADD CONSTRAINT plg_inventory_fulfillment_items_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_measurement_units\n ADD CONSTRAINT plg_inventory_measurement_units_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_operations\n ADD CONSTRAINT plg_inventory_operations_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_operations\n ADD CONSTRAINT plg_inventory_operations_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_operations\n ADD CONSTRAINT plg_inventory_operations_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES public.plg_inventory_product_categories(id);\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_product_categories\n ADD CONSTRAINT plg_inventory_product_categories_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_category_id_fkey FOREIGN KEY (category_id) REFERENCES public.plg_inventory_product_categories(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_default_location_id_fkey FOREIGN KEY (default_location_id) REFERENCES public.plg_inventory_stock_locations(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_measurement_unit_id_fkey FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_purchase_unit_id_fkey FOREIGN KEY (purchase_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_supplier_id_fkey FOREIGN KEY (supplier_id) REFERENCES public.people(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_default_location_id_fkey FOREIGN KEY (default_location_id) REFERENCES public.plg_inventory_stock_locations(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_measurement_unit_id_fkey FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id);\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_product_settings\n ADD CONSTRAINT plg_inventory_product_settings_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_recipe_groups\n ADD CONSTRAINT plg_inventory_recipe_groups_recipe_id_fkey FOREIGN KEY (recipe_id) REFERENCES public.plg_inventory_recipes(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_recipe_groups\n ADD CONSTRAINT plg_inventory_recipe_groups_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_group_id_fkey FOREIGN KEY (group_id) REFERENCES public.plg_inventory_recipe_groups(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_recipe_id_fkey FOREIGN KEY (recipe_id) REFERENCES public.plg_inventory_recipes(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_recipe_ingredients\n ADD CONSTRAINT plg_inventory_recipe_ingredients_unit_fk FOREIGN KEY (unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_recipes\n ADD CONSTRAINT plg_inventory_recipes_yield_unit_fk FOREIGN KEY (yield_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_measurement_unit_id_fkey FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_movement_id_fkey FOREIGN KEY (movement_id) REFERENCES public.plg_inventory_stock_movements(id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_reversal_movement_id_fkey FOREIGN KEY (reversal_movement_id) REFERENCES public.plg_inventory_stock_movements(id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_stock_location_id_fkey FOREIGN KEY (stock_location_id) REFERENCES public.plg_inventory_stock_locations(id);\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_reservations\n ADD CONSTRAINT plg_inventory_reservations_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_stock_locations\n ADD CONSTRAINT plg_inventory_stock_locations_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_destination_location_id_fkey FOREIGN KEY (destination_location_id) REFERENCES public.plg_inventory_stock_locations(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_measurement_unit_id_fkey FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_operation_fk FOREIGN KEY (operation_id) REFERENCES public.plg_inventory_operations(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_reverses_movement_id_fkey FOREIGN KEY (reverses_movement_id) REFERENCES public.plg_inventory_stock_movements(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_stock_location_id_fkey FOREIGN KEY (source_location_id) REFERENCES public.plg_inventory_stock_locations(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_supplier_id_fkey FOREIGN KEY (supplier_id) REFERENCES public.people(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_stock_movements\n ADD CONSTRAINT plg_inventory_stock_movements_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_measurement_unit_id_fkey FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_stock_location_id_fkey FOREIGN KEY (stock_location_id) REFERENCES public.plg_inventory_stock_locations(id);\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_stock_positions\n ADD CONSTRAINT plg_inventory_stock_positions_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_from_unit_id_fkey FOREIGN KEY (from_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_owner_fk FOREIGN KEY (tenant_id, owner_id) REFERENCES app.memberships(tenant_id, user_id) ON DELETE SET NULL;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_to_unit_id_fkey FOREIGN KEY (to_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.plg_inventory_unit_conversions\n ADD CONSTRAINT plg_inventory_unit_conversions_unit_fk FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n\n\n-- ── trigger ─────────────────────────────────────────────────────────────\n\nCREATE TRIGGER fulfillments_emit_completed AFTER INSERT OR UPDATE OF status ON public.fulfillments FOR EACH ROW EXECUTE FUNCTION public.trg_fulfillments_emit();\n\nCREATE TRIGGER plg_inventory_count_items_updated_at BEFORE UPDATE ON public.plg_inventory_count_items FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_count_sessions_updated_at BEFORE UPDATE ON public.plg_inventory_count_sessions FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_fulfillment_items_inherit BEFORE INSERT OR UPDATE OF item_id ON public.plg_inventory_fulfillment_items FOR EACH ROW EXECUTE FUNCTION public.trg_plg_inventory_fulfillment_items_inherit();\n\nCREATE TRIGGER plg_inventory_fulfillment_items_updated_at BEFORE UPDATE ON public.plg_inventory_fulfillment_items FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_measurement_units_updated_at BEFORE UPDATE ON public.plg_inventory_measurement_units FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_operations_internal_only BEFORE INSERT OR DELETE OR UPDATE ON public.plg_inventory_operations FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\n\nCREATE TRIGGER plg_inventory_operations_updated_at BEFORE UPDATE ON public.plg_inventory_operations FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_product_categories_updated_at BEFORE UPDATE ON public.plg_inventory_product_categories FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_product_settings_updated_at BEFORE UPDATE ON public.plg_inventory_product_settings FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_recipes_updated_at BEFORE UPDATE ON public.plg_inventory_recipes FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_reservations_internal_only BEFORE INSERT OR DELETE OR UPDATE ON public.plg_inventory_reservations FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\n\nCREATE TRIGGER plg_inventory_reservations_one_per_source BEFORE INSERT OR UPDATE OF status, source_type, source_id, line_no ON public.plg_inventory_reservations FOR EACH ROW EXECUTE FUNCTION app.inventory_reservation_one_per_source();\n\nCREATE TRIGGER plg_inventory_reservations_updated_at BEFORE UPDATE ON public.plg_inventory_reservations FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_stock_locations_before_update BEFORE UPDATE ON public.plg_inventory_stock_locations FOR EACH ROW EXECUTE FUNCTION app.inventory_locations_before_update();\n\nCREATE TRIGGER plg_inventory_stock_locations_updated_at BEFORE UPDATE ON public.plg_inventory_stock_locations FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_stock_movements_after_insert AFTER INSERT ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_after_insert();\n\nCREATE TRIGGER plg_inventory_stock_movements_append_only BEFORE DELETE OR UPDATE ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_append_only();\n\nCREATE TRIGGER plg_inventory_stock_movements_before_insert BEFORE INSERT ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_before_insert();\n\nCREATE TRIGGER plg_inventory_stock_movements_internal_only BEFORE INSERT ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\n\nCREATE TRIGGER plg_inventory_stock_movements_source_required BEFORE INSERT ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION app.inventory_movement_source_required();\n\nCREATE TRIGGER plg_inventory_stock_movements_updated_at BEFORE UPDATE ON public.plg_inventory_stock_movements FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_stock_positions_internal_only BEFORE INSERT OR DELETE OR UPDATE ON public.plg_inventory_stock_positions FOR EACH ROW EXECUTE FUNCTION app.inventory_internal_only();\n\nCREATE TRIGGER plg_inventory_stock_positions_updated_at BEFORE UPDATE ON public.plg_inventory_stock_positions FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER plg_inventory_unit_conversions_updated_at BEFORE UPDATE ON public.plg_inventory_unit_conversions FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nCREATE TRIGGER tenants_inventory_seed_units AFTER INSERT ON public.tenants FOR EACH ROW EXECUTE FUNCTION app.trg_inventory_seed_units_for_tenant();\n\n\n-- ── row security ────────────────────────────────────────────────────────\n\nALTER TABLE public.plg_inventory_count_items ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_count_sessions ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_fulfillment_items ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_measurement_units ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_operations ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_product_categories ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_product_details ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_product_settings ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_recipe_groups ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_recipe_ingredients ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_recipes ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_reservations ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_stock_locations ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_stock_movements ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_stock_positions ENABLE ROW LEVEL SECURITY;\n\nALTER TABLE public.plg_inventory_unit_conversions ENABLE ROW LEVEL SECURITY;\n\n\n-- ── policy ──────────────────────────────────────────────────────────────\n\nCREATE POLICY plg_inventory_count_items_authz_delete ON public.plg_inventory_count_items FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_items.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_item'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_item'::text, plg_inventory_count_items.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_items.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_count_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_items_authz_insert ON public.plg_inventory_count_items FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_items.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_count_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_items_authz_select ON public.plg_inventory_count_items FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_items.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_item'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_item'::text, plg_inventory_count_items.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_items.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_count_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_items_authz_update ON public.plg_inventory_count_items FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_items.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_item'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_item'::text, plg_inventory_count_items.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_items.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_count_items.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_items.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_count_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_sessions_authz_delete ON public.plg_inventory_count_sessions FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_sessions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_session'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_session'::text, plg_inventory_count_sessions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_sessions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_count_sessions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_sessions_authz_insert ON public.plg_inventory_count_sessions FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_sessions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_count_sessions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_sessions_authz_select ON public.plg_inventory_count_sessions FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_sessions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_session'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_session'::text, plg_inventory_count_sessions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_sessions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_count_sessions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_count_sessions_authz_update ON public.plg_inventory_count_sessions FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_sessions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.count_session'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.count_session'::text, plg_inventory_count_sessions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_count_sessions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_count_sessions.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_count_sessions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_count_sessions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_fulfillment_items_authz_delete ON public.plg_inventory_fulfillment_items FOR DELETE TO authenticated USING (((item_id IN ( SELECT i.id\n FROM public.items i)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_fulfillment_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_fulfillment_items_authz_insert ON public.plg_inventory_fulfillment_items FOR INSERT TO authenticated WITH CHECK (((item_id IN ( SELECT i.id\n FROM public.items i)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_fulfillment_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_fulfillment_items_authz_select ON public.plg_inventory_fulfillment_items FOR SELECT TO authenticated USING ((item_id IN ( SELECT i.id\n FROM public.items i)));\n\nCREATE POLICY plg_inventory_fulfillment_items_authz_update ON public.plg_inventory_fulfillment_items FOR UPDATE TO authenticated USING (((item_id IN ( SELECT i.id\n FROM public.items i)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_fulfillment_items.unit_id) AS has_permission))) WITH CHECK (((item_id IN ( SELECT i.id\n FROM public.items i)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_fulfillment_items.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_measurement_units_authz_delete ON public.plg_inventory_measurement_units FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_measurement_units.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.measurement_unit'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.measurement_unit'::text, plg_inventory_measurement_units.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_measurement_units.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_measurement_units.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_measurement_units_authz_insert ON public.plg_inventory_measurement_units FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_measurement_units.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_measurement_units.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_measurement_units_authz_select ON public.plg_inventory_measurement_units FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_measurement_units.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.measurement_unit'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.measurement_unit'::text, plg_inventory_measurement_units.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_measurement_units.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_measurement_units.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_measurement_units_authz_update ON public.plg_inventory_measurement_units FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_measurement_units.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.measurement_unit'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.measurement_unit'::text, plg_inventory_measurement_units.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_measurement_units.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_measurement_units.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_measurement_units.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_measurement_units.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_operations_authz_delete ON public.plg_inventory_operations FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_operations.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.operation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.operation'::text, plg_inventory_operations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_operations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_operations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_operations_authz_insert ON public.plg_inventory_operations FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_operations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_operations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_operations_authz_select ON public.plg_inventory_operations FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_operations.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.operation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.operation'::text, plg_inventory_operations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_operations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_operations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_operations_authz_update ON public.plg_inventory_operations FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_operations.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.operation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.operation'::text, plg_inventory_operations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_operations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_operations.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_operations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_operations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_categories_authz_delete ON public.plg_inventory_product_categories FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_categories.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_category'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_category'::text, plg_inventory_product_categories.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_categories.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_product_categories.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_categories_authz_insert ON public.plg_inventory_product_categories FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_categories.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_product_categories.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_categories_authz_select ON public.plg_inventory_product_categories FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_categories.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_category'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_category'::text, plg_inventory_product_categories.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_categories.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_product_categories.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_categories_authz_update ON public.plg_inventory_product_categories FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_categories.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_category'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_category'::text, plg_inventory_product_categories.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_categories.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_product_categories.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_categories.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_product_categories.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_categories_delete ON public.plg_inventory_product_categories FOR DELETE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_categories_insert ON public.plg_inventory_product_categories FOR INSERT TO authenticated WITH CHECK ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_categories_select ON public.plg_inventory_product_categories FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_categories_update ON public.plg_inventory_product_categories FOR UPDATE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_details_delete ON public.plg_inventory_product_details FOR DELETE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_details_insert ON public.plg_inventory_product_details FOR INSERT TO authenticated WITH CHECK ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_details_select ON public.plg_inventory_product_details FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_details_update ON public.plg_inventory_product_details FOR UPDATE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_product_settings_authz_delete ON public.plg_inventory_product_settings FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_settings.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_settings'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_settings'::text, plg_inventory_product_settings.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_settings.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_product_settings.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_settings_authz_insert ON public.plg_inventory_product_settings FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_settings.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_product_settings.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_settings_authz_select ON public.plg_inventory_product_settings FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_settings.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_settings'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_settings'::text, plg_inventory_product_settings.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_settings.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_product_settings.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_product_settings_authz_update ON public.plg_inventory_product_settings FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_settings.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.product_settings'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.product_settings'::text, plg_inventory_product_settings.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_product_settings.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_product_settings.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_product_settings.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_product_settings.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_recipe_groups_delete ON public.plg_inventory_recipe_groups FOR DELETE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_groups_insert ON public.plg_inventory_recipe_groups FOR INSERT TO authenticated WITH CHECK ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_groups_select ON public.plg_inventory_recipe_groups FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_groups_update ON public.plg_inventory_recipe_groups FOR UPDATE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_ingredients_delete ON public.plg_inventory_recipe_ingredients FOR DELETE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_ingredients_insert ON public.plg_inventory_recipe_ingredients FOR INSERT TO authenticated WITH CHECK ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_ingredients_select ON public.plg_inventory_recipe_ingredients FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipe_ingredients_update ON public.plg_inventory_recipe_ingredients FOR UPDATE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipes_authz_delete ON public.plg_inventory_recipes FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_recipes.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.recipe'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.recipe'::text, plg_inventory_recipes.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_recipes.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_recipes.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_recipes_authz_insert ON public.plg_inventory_recipes FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_recipes.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_recipes.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_recipes_authz_select ON public.plg_inventory_recipes FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_recipes.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.recipe'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.recipe'::text, plg_inventory_recipes.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_recipes.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_recipes.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_recipes_authz_update ON public.plg_inventory_recipes FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_recipes.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.recipe'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.recipe'::text, plg_inventory_recipes.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_recipes.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_recipes.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_recipes.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_recipes.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_recipes_delete ON public.plg_inventory_recipes FOR DELETE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipes_insert ON public.plg_inventory_recipes FOR INSERT TO authenticated WITH CHECK ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipes_select ON public.plg_inventory_recipes FOR SELECT TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_recipes_update ON public.plg_inventory_recipes FOR UPDATE TO authenticated USING ((tenant_id IN ( SELECT public.user_tenant_ids() AS user_tenant_ids)));\n\nCREATE POLICY plg_inventory_reservations_authz_delete ON public.plg_inventory_reservations FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_reservations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.reservation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.reservation'::text, plg_inventory_reservations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_reservations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_reservations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_reservations_authz_insert ON public.plg_inventory_reservations FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_reservations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_reservations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_reservations_authz_select ON public.plg_inventory_reservations FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_reservations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.reservation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.reservation'::text, plg_inventory_reservations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_reservations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_reservations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_reservations_authz_update ON public.plg_inventory_reservations FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_reservations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.reservation'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.reservation'::text, plg_inventory_reservations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_reservations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_reservations.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_reservations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_reservations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_locations_authz_delete ON public.plg_inventory_stock_locations FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_locations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_location'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_location'::text, plg_inventory_stock_locations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_locations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_stock_locations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_locations_authz_insert ON public.plg_inventory_stock_locations FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_locations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_stock_locations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_locations_authz_select ON public.plg_inventory_stock_locations FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_locations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_location'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_location'::text, plg_inventory_stock_locations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_locations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_stock_locations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_locations_authz_update ON public.plg_inventory_stock_locations FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_locations.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_location'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_location'::text, plg_inventory_stock_locations.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_locations.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_locations.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_locations.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_locations.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_movements_authz_delete ON public.plg_inventory_stock_movements FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_movements.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_movement'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_movement'::text, plg_inventory_stock_movements.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_movements.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_stock_movements.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_movements_authz_insert ON public.plg_inventory_stock_movements FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_movements.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_stock_movements.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_movements_authz_select ON public.plg_inventory_stock_movements FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_movements.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_movement'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_movement'::text, plg_inventory_stock_movements.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_movements.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_stock_movements.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_movements_authz_update ON public.plg_inventory_stock_movements FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_movements.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_movement'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_movement'::text, plg_inventory_stock_movements.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_movements.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_movements.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_movements.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_movements.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_positions_authz_delete ON public.plg_inventory_stock_positions FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_positions.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_position'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_position'::text, plg_inventory_stock_positions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_positions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_stock_positions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_positions_authz_insert ON public.plg_inventory_stock_positions FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_positions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_stock_positions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_positions_authz_select ON public.plg_inventory_stock_positions FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_positions.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_position'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_position'::text, plg_inventory_stock_positions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_positions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_stock_positions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_stock_positions_authz_update ON public.plg_inventory_stock_positions FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ( SELECT app.has_unit(plg_inventory_stock_positions.unit_id) AS has_unit) AND ((NOT ( SELECT app.owner_scoped('inventory.stock_position'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.stock_position'::text, plg_inventory_stock_positions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_stock_positions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_positions.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_stock_positions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_stock_positions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_unit_conversions_authz_delete ON public.plg_inventory_unit_conversions FOR DELETE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_unit_conversions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.unit_conversion'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.unit_conversion'::text, plg_inventory_unit_conversions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.delete'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_unit_conversions_authz_insert ON public.plg_inventory_unit_conversions FOR INSERT TO authenticated WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_unit_conversions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.create'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_unit_conversions_authz_select ON public.plg_inventory_unit_conversions FOR SELECT TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_unit_conversions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.unit_conversion'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.unit_conversion'::text, plg_inventory_unit_conversions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.read'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)));\n\nCREATE POLICY plg_inventory_unit_conversions_authz_update ON public.plg_inventory_unit_conversions FOR UPDATE TO authenticated USING (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_unit_conversions.unit_id) AS has_unit)) AND ((NOT ( SELECT app.owner_scoped('inventory.unit_conversion'::text) AS owner_scoped)) OR (owner_id IS NULL) OR (owner_id = ( SELECT auth.uid() AS uid)) OR ( SELECT app.has_grant('inventory.unit_conversion'::text, plg_inventory_unit_conversions.id, ARRAY['shared_with'::text]) AS has_grant) OR ( SELECT app.has_permission('inventory.read_all'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_unit_conversions.unit_id) AS has_permission))) WITH CHECK (((tenant_id = ( SELECT app.current_tenant_id() AS current_tenant_id)) AND ((unit_id IS NULL) OR ( SELECT app.has_unit(plg_inventory_unit_conversions.unit_id) AS has_unit)) AND ( SELECT app.has_permission('inventory.edit'::text, plg_inventory_unit_conversions.unit_id) AS has_permission)));\n\n\n-- ── acl ─────────────────────────────────────────────────────────────────\n\nREVOKE ALL ON FUNCTION app.inventory_apply_to_position(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date, p_effect numeric, p_unit_cost numeric, p_measurement_unit uuid, OUT o_quantity numeric, OUT o_unit_cost numeric) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_authorize_location(p_tenant uuid, p_location uuid, p_perm text) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_available(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_begin_operation(p_tenant uuid, p_kind text, p_key text, p_request jsonb, OUT op_id uuid, OUT existing jsonb) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_check_lines(p_lines jsonb) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_consume_order_item(p_tenant uuid, p_order uuid, p_order_item uuid, p_unit uuid, p_product uuid, p_quantity numeric, p_actor uuid) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_default_variant(p_tenant uuid, p_product uuid) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_finish_operation(p_tenant uuid, p_op uuid, p_kind text, p_key text, p_result jsonb, p_audit jsonb) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_movement_json(p_id uuid) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_parse_line(p_tenant uuid, p_line jsonb, p_mode text, OUT product_id uuid, OUT quantity numeric, OUT unit_cost numeric, OUT batch_number text, OUT expiration_date date, OUT measurement_unit_id uuid, OUT declared jsonb, OUT notes text) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_position_json(p_tenant uuid, p_product uuid, p_location uuid, p_batch text, p_expiry date) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_product_label(p_product uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION app.inventory_product_label(p_product uuid) TO authenticated;\nGRANT ALL ON FUNCTION app.inventory_product_label(p_product uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION app.inventory_require_tenant() FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_reservation_json(p_id uuid) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_reservation_one_per_source() FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION app.inventory_sync_archetype_balance(p_tenant uuid, p_product uuid, p_location uuid, p_delta numeric) FROM PUBLIC;\n\nREVOKE ALL ON FUNCTION public.agent_inventory_upsert_recipe(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.agent_inventory_upsert_recipe(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.agent_inventory_upsert_recipe(p_tenant_id uuid, p_actor_user_id uuid, p_payload jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.app_product_stock_owner(p_tenant uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.app_product_stock_owner(p_tenant uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_adjust(p_location uuid, p_lines jsonb, p_reason text, p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_adjust(p_location uuid, p_lines jsonb, p_reason text, p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_adjust(p_location uuid, p_lines jsonb, p_reason text, p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_close_count_session(p_session_id uuid, p_reason text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_close_count_session(p_session_id uuid, p_reason text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_close_count_session(p_session_id uuid, p_reason text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_confirm(p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_confirm(p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_confirm(p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_convert(p_tenant uuid, p_product uuid, p_qty numeric, p_from_unit uuid, p_to_unit uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_convert(p_tenant uuid, p_product uuid, p_qty numeric, p_from_unit uuid, p_to_unit uuid) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_convert(p_tenant uuid, p_product uuid, p_qty numeric, p_from_unit uuid, p_to_unit uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_open_count_session(p_stock_location_id uuid, p_category_id uuid, p_reference text, p_blind boolean, p_notes text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_open_count_session(p_stock_location_id uuid, p_category_id uuid, p_reference text, p_blind boolean, p_notes text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_open_count_session(p_stock_location_id uuid, p_category_id uuid, p_reference text, p_blind boolean, p_notes text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb, p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb, p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb, p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_register_product_image(p_product uuid, p_storage_path text, p_public_url text, p_file_name text, p_file_size integer, p_mime_type text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_register_product_image(p_product uuid, p_storage_path text, p_public_url text, p_file_name text, p_file_size integer, p_mime_type text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_register_product_image(p_product uuid, p_storage_path text, p_public_url text, p_file_name text, p_file_size integer, p_mime_type text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_reserve(p_source_type text, p_source_id uuid, p_lines jsonb, p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_reserve(p_source_type text, p_source_id uuid, p_lines jsonb, p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_reserve(p_source_type text, p_source_id uuid, p_lines jsonb, p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_reverse(p_idempotency_key text, p_reason text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_reverse(p_idempotency_key text, p_reason text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_reverse(p_idempotency_key text, p_reason text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_seed_measurement_units() FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_seed_measurement_units() TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_seed_measurement_units() TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_seed_measurement_units(p_tenant uuid) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_seed_measurement_units(p_tenant uuid) TO service_role;\n\nREVOKE ALL ON FUNCTION public.inventory_transfer(p_from_location uuid, p_to_location uuid, p_lines jsonb, p_idempotency_key text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_transfer(p_from_location uuid, p_to_location uuid, p_lines jsonb, p_idempotency_key text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_transfer(p_from_location uuid, p_to_location uuid, p_lines jsonb, p_idempotency_key text) TO service_role;\n\nREVOKE ALL ON FUNCTION public.plg_inventory_on_fulfillment_completed(p_event jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.plg_inventory_on_fulfillment_completed(p_event jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.plg_inventory_on_order_completed(p_event jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.plg_inventory_on_order_completed(p_event jsonb) TO service_role;\n\nREVOKE ALL ON FUNCTION public.trg_fulfillments_emit() FROM PUBLIC;\nGRANT ALL ON FUNCTION public.trg_fulfillments_emit() TO service_role;\n\nREVOKE ALL ON FUNCTION public.trg_plg_inventory_fulfillment_items_inherit() FROM PUBLIC;\nGRANT ALL ON FUNCTION public.trg_plg_inventory_fulfillment_items_inherit() TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_count_items TO anon;\nGRANT ALL ON TABLE public.plg_inventory_count_items TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_count_items TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_count_sessions TO anon;\nGRANT ALL ON TABLE public.plg_inventory_count_sessions TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_count_sessions TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_fulfillment_items TO anon;\nGRANT ALL ON TABLE public.plg_inventory_fulfillment_items TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_fulfillment_items TO service_role;\n\nGRANT ALL ON TABLE public.plg_inventory_measurement_units TO service_role;\nGRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.plg_inventory_measurement_units TO authenticated;\n\nGRANT ALL ON TABLE public.plg_inventory_operations TO service_role;\nGRANT SELECT ON TABLE public.plg_inventory_operations TO authenticated;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_product_categories TO anon;\nGRANT ALL ON TABLE public.plg_inventory_product_categories TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_product_categories TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_product_details TO anon;\nGRANT ALL ON TABLE public.plg_inventory_product_details TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_product_details TO service_role;\n\nGRANT ALL ON TABLE public.plg_inventory_product_settings TO service_role;\nGRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.plg_inventory_product_settings TO authenticated;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_recipe_groups TO anon;\nGRANT ALL ON TABLE public.plg_inventory_recipe_groups TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_recipe_groups TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_recipe_ingredients TO anon;\nGRANT ALL ON TABLE public.plg_inventory_recipe_ingredients TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_recipe_ingredients TO service_role;\n\nGRANT MAINTAIN ON TABLE public.plg_inventory_recipes TO anon;\nGRANT ALL ON TABLE public.plg_inventory_recipes TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_recipes TO service_role;\n\nGRANT ALL ON TABLE public.plg_inventory_reservations TO service_role;\nGRANT SELECT ON TABLE public.plg_inventory_reservations TO authenticated;\n\nGRANT ALL ON TABLE public.plg_inventory_stock_locations TO service_role;\nGRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.plg_inventory_stock_locations TO authenticated;\n\nGRANT ALL ON TABLE public.plg_inventory_stock_movements TO service_role;\nGRANT SELECT ON TABLE public.plg_inventory_stock_movements TO authenticated;\n\nGRANT ALL ON TABLE public.plg_inventory_stock_positions TO service_role;\nGRANT SELECT ON TABLE public.plg_inventory_stock_positions TO authenticated;\n\nGRANT ALL ON TABLE public.plg_inventory_unit_conversions TO service_role;\nGRANT SELECT,INSERT,DELETE,UPDATE ON TABLE public.plg_inventory_unit_conversions TO authenticated;\n\nGRANT ALL ON TABLE public.v_inventory_balances TO authenticated;\nGRANT ALL ON TABLE public.v_inventory_balances TO service_role;\n\nGRANT ALL ON TABLE public.v_inventory_low_stock TO authenticated;\nGRANT ALL ON TABLE public.v_inventory_low_stock TO service_role;\n\nGRANT ALL ON TABLE public.v_inventory_movements TO authenticated;\nGRANT ALL ON TABLE public.v_inventory_movements TO service_role;\n\nGRANT ALL ON TABLE public.v_inventory_product_totals TO authenticated;\nGRANT ALL ON TABLE public.v_inventory_product_totals TO service_role;\n\nGRANT MAINTAIN ON TABLE public.v_inventory_products TO anon;\nGRANT ALL ON TABLE public.v_inventory_products TO authenticated;\nGRANT ALL ON TABLE public.v_inventory_products TO service_role;\n\nGRANT MAINTAIN ON TABLE public.v_stock_movements TO anon;\nGRANT ALL ON TABLE public.v_stock_movements TO authenticated;\nGRANT ALL ON TABLE public.v_stock_movements TO service_role;\n\n\n-- ── comment ─────────────────────────────────────────────────────────────\n\nCOMMENT ON FUNCTION app.inventory_default_variant(p_tenant uuid, p_product uuid) IS 'Which variant a product-level movement belongs to (#276): the default one, else the first active. NULL when the catalogue has none — the movement then writes no balance rather than inventing a variant.';\n\nCOMMENT ON FUNCTION app.inventory_sync_archetype_balance(p_tenant uuid, p_product uuid, p_location uuid, p_delta numeric) IS 'Applies a movement''s delta to public.stock_balances at the archetype''s grain (#276). Batch and expiry stay with this plugin; the archetype gets the number.';\n\nCOMMENT ON FUNCTION public.plg_inventory_on_fulfillment_completed(p_event jsonb) IS 'Consumes a completed DELIVERY through the same door a completed sale uses (PRD 05). The quantity is the delivery line''s own, so an order of two that delivers one moves the balance by one — which a status column on the sold line could never express.';\n\nCOMMENT ON FUNCTION public.plg_inventory_on_order_completed(p_event jsonb) IS 'Consumes a completed order from the durable event log (024), skipping any line a delivery document already covered (PRD 05). Active recipes still expand into ingredients; a product without a recipe still consumes its own stock.';\n\nCOMMENT ON COLUMN public.plg_inventory_count_items.system_quantity IS 'What the system believed when the session OPENED — never re-read at close.';\n\nCOMMENT ON COLUMN public.plg_inventory_count_items.counted_quantity IS 'NULL means nobody counted this line. It is not zero and never emits an adjustment.';\n\nCOMMENT ON COLUMN public.plg_inventory_count_items.movement_id IS 'The adjustment this line already emitted. Set exactly once — the per-line idempotency key of the close.';\n\nCOMMENT ON TABLE public.plg_inventory_fulfillment_items IS 'What only a delivery line has (PRD 05): batch, expiry, who handed it over and from which stock location. Composite FK on (item_id, parent_kind) — the database refuses it over an invoice line, which is why this table has no tax column and that one has no batch.';\n\nCOMMENT ON TABLE public.plg_inventory_operations IS 'Idempotency ledger of the inventory RPCs: (tenant, kind, idempotency_key) → stored result. A replay returns the stored result and has no second effect.';\n\nCOMMENT ON COLUMN public.plg_inventory_product_details.conversion_factor IS 'How many measurement_unit_id fit in one purchase_unit_id. 1 when the product is bought and consumed in the same unit.';\n\nCOMMENT ON COLUMN public.plg_inventory_product_details.purpose IS 'purchase | sale | both | menu. Unconstrained: the vocabulary is per-app labels, not a schema fact.';\n\nCOMMENT ON TABLE public.plg_inventory_product_settings IS 'Per-product inventory settings (min/max quantity, stock unit, default location), tenant-wide (unit_id NULL) or per unit. Replaces products.min_stock.';\n\nCOMMENT ON COLUMN public.plg_inventory_recipes.metadata IS 'What the assistant could not resolve: {unmatchedIngredients:[{name,quantity,notes}], productHint}.';\n\nCOMMENT ON TABLE public.plg_inventory_reservations IS 'Consumption hooks: inventory_reserve → inventory_confirm (one out movement, exactly once) → inventory_reverse. Keyed by the source item through idempotency_key.';\n\nCOMMENT ON TABLE public.plg_inventory_stock_movements IS 'Append-only stock ledger (PRD 06). quantity is signed: the effect on the position at (product, source_location, batch, expiry); a transfer or reversed transfer applies -quantity at destination_location. Written only by the inventory_* RPCs.';\n\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.stock_location_id IS 'DEPRECATED compat mirror of source_location_id, kept so the applied 004_stock_movement_view stays replay-safe. Dropped at the cut-over.';\n\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.movement_type IS 'DEPRECATED compat mirror of kind, kept so the applied 004_stock_movement_view stays replay-safe. Dropped at the cut-over.';\n\nCOMMENT ON TABLE public.plg_inventory_stock_positions IS 'Derived balances per (product, location, batch, expiry). Maintained by the movements writer trigger; never written by app code. Read through v_inventory_balances / v_inventory_product_totals.';\n\nCOMMENT ON COLUMN public.plg_inventory_stock_positions.unit_type IS 'base | purchase | content — which of the product''s units this quantity is counted in.';\n\nCOMMENT ON TABLE public.plg_inventory_unit_conversions IS 'from_unit → to_unit × factor, tenant-wide (product_id NULL) or product-specific (a 250 mL bottle: bottle → mL × 250). Resolved by public.inventory_convert().';\n\nCOMMENT ON VIEW public.v_inventory_balances IS 'Balances per (product, location, batch, expiry) with reserved/available. security_invoker: the caller sees the units she has access to (inventory.read).';\n\nCOMMENT ON VIEW public.v_inventory_low_stock IS 'Products at or below the min quantity of plg_inventory_product_settings (tenant-wide row: unit_id NULL; per-unit rows).';\n\nCOMMENT ON VIEW public.v_inventory_movements IS 'The append-only ledger with names. movement_type is the SDK legacy label (entry/exit/loss/adjustment/transfer); kind is canonical.';\n\nCOMMENT ON VIEW public.v_inventory_product_totals IS 'Balances per product across the units the caller sees. Replaces products.stock as the read model.';\n\nCOMMENT ON VIEW public.v_inventory_products IS 'The catalogue with its balance (027): every products column, plus stock, available, reserved and min_stock DERIVED from the ledger and the product settings. It replaces the products.stock and products.min_stock columns spine 188 dropped — same names, same shape, one writer.';\n\n\n-- ── default privileges: restore ─────────────────────────────────────────\n-- Put back, so the NEXT thing installed inherits what the chain had.\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT MAINTAIN ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role$stmt$;\nEND $dp$;\n\nDO $dp$ BEGIN\n EXECUTE $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEXCEPTION WHEN insufficient_privilege OR undefined_object THEN\n RAISE NOTICE 'baseline: not ours to set — %', $stmt$--\n-- PostgreSQL database dump complete\n--$stmt$;\nEND $dp$;\n`\n\nexport const MIGRATION_001_THE_USAGE_THAT_LEFT_STOCK_CAN_BE_AUDITED = `-- 001_the_usage_that_left_stock_can_be_audited.sql\n--\n-- AUDITORIA DE USO. No V1 o consumo declarado no atendimento fica numa FILA e\n-- só baixa o estoque depois que alguém aprova. O V2 não tem essa fila e não\n-- deveria ter: \\`order.completed\\` consome a receita no mesmo instante, pelo log\n-- de eventos, e é isso que faz o saldo e a venda contarem a mesma história.\n--\n-- O QUE A TELA DO V1 REALMENTE ENTREGA não é o represamento — é a PERGUNTA:\n-- \"o que o profissional disse ter usado bate com o padrão do serviço?\". No V1\n-- ela era feita antes da baixa; aqui é feita depois. A resposta é a mesma, e a\n-- correção continua possível porque o razão é append-only: corrigir é lançar o\n-- ajuste da diferença, nunca reescrever o que já saiu.\n--\n-- POR QUE UMA VISTA, E NÃO UMA TABELA DE AUDITORIA. Uma fila própria seria um\n-- segundo lugar guardando a mesma quantidade, e os dois divergem no primeiro\n-- estorno. Tudo de que a auditoria precisa já está escrito:\n--\n-- \\`plg_inventory_stock_movements\\` guarda \\`source_item_type='order_item'\\` e\n-- \\`source_item_id\\` apontando para a linha vendida, com \\`unit_cost\\`,\n-- \\`total_cost\\` e a localização de onde saiu.\n--\n-- \\`plg_inventory_recipes\\` + \\`_recipe_ingredients\\` guardam o PADRÃO — o mesmo\n-- número que \\`app.inventory_consume_order_item\\` usou para calcular a baixa.\n--\n-- \\`items.assignee_id\\` guarda QUEM executou (financeiro 019 já provou o elo),\n-- e \\`orders.party_id\\` guarda para quem.\n--\n-- A GRANULARIDADE É (linha vendida × produto), não o movimento. Um consumo se\n-- parte em vários movimentos quando o FIFO atravessa lotes: três linhas de\n-- razão para um frasco só confundiriam quem confere.\n--\n-- O PADRÃO É O DE HOJE. A receita pode ter mudado desde o atendimento, e a\n-- vista mostra a receita vigente — igual ao V1, que também lia o cadastro atual.\n-- Divergência antiga que sumiu porque a receita mudou é ruído, não achado.\n\nCREATE OR REPLACE VIEW public.v_inventory_usage_audit\nWITH (security_invoker = 'true') AS\nWITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\n -- o razão guarda saída como negativo; quem confere pensa em positivo\n sum(- m.quantity) AS posted_quantity,\n sum(m.total_cost) AS total_cost,\n min(m.created_at) AS used_at,\n min(m.movement_date) AS movement_date,\n (array_agg(m.source_location_id ORDER BY m.created_at, m.id))[1] AS stock_location_id,\n count(DISTINCT m.source_location_id)::int AS location_count,\n (array_agg(m.measurement_unit_id ORDER BY m.created_at, m.id))[1] AS measurement_unit_id,\n (array_agg(m.metadata ->> 'recipe_id' ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM public.plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'\n AND m.source_item_id IS NOT NULL\n AND m.kind = 'out'\n -- estornado não é consumo: devolver ao estoque apaga a linha da fila\n AND NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id\n )\n GROUP BY m.tenant_id, m.unit_id, m.source_item_id, m.product_id\n), corrected AS (\n SELECT c.tenant_id,\n c.source_item_id AS item_id,\n c.product_id,\n -- devolver ao estoque é ajuste positivo, e reduz o consumido\n sum(- c.quantity) AS correction_delta,\n -- o razão guarda custo sempre positivo; o sinal vem da quantidade\n sum(- sign(c.quantity) * c.total_cost) AS correction_cost,\n max(c.created_at) AS corrected_at,\n (array_agg(c.reason ORDER BY c.created_at DESC, c.id DESC))[1] AS correction_reason\n FROM public.plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'\n AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n)\nSELECT c.tenant_id,\n c.unit_id,\n c.item_id,\n c.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n c.used_at,\n c.movement_date,\n c.posted_quantity::numeric(14,4) AS posted_quantity,\n (c.posted_quantity + coalesce(k.correction_delta, 0))::numeric(14,4) AS net_quantity,\n std.standard_quantity::numeric(14,4) AS standard_quantity,\n CASE WHEN std.standard_quantity IS NULL THEN NULL\n ELSE ((c.posted_quantity + coalesce(k.correction_delta, 0))\n - std.standard_quantity)::numeric(14,4)\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n -- o custo acompanha a conclusão da auditoria, não o que foi lançado:\n -- devolver um frasco devolve o custo dele junto\n (c.total_cost + coalesce(k.correction_cost, 0))::numeric(16,4) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\n -- mais de uma posição quer dizer que o FIFO atravessou lotes\n c.location_count,\n r.id AS recipe_id,\n r.name AS recipe_name,\n i.order_id,\n i.name AS item_name,\n o.reference_number AS order_reference,\n i.assignee_id AS performed_by_id,\n perf.name AS performed_by_name,\n o.party_id AS customer_id,\n cust.name AS customer_name,\n k.corrected_at,\n k.correction_reason,\n (k.item_id IS NOT NULL) AS is_corrected\n FROM consumed c\n LEFT JOIN corrected k\n ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN public.products p ON p.id = c.product_id\n LEFT JOIN public.plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN public.plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n -- A linha vendida e seu pedido chegam por LEFT JOIN de propósito: quem lê o\n -- estoque pode não ler a venda, e nesse caso a linha aparece sem o nome do\n -- profissional em vez de desaparecer da conferência.\n LEFT JOIN public.items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN public.orders o ON o.id = i.order_id\n LEFT JOIN public.people perf ON perf.id = i.assignee_id\n LEFT JOIN public.people cust ON cust.id = o.party_id\n LEFT JOIN public.plg_inventory_recipes r\n ON r.id = nullif(c.recipe_id, '')::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL (\n SELECT CASE\n WHEN r.id IS NOT NULL AND coalesce(r.yield_quantity, 0) > 0 THEN (\n SELECT round(sum(ri.quantity) * coalesce(i.quantity, 1) / r.yield_quantity, 4)\n FROM public.plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id\n AND ri.recipe_id = r.id\n AND ri.product_id = c.product_id\n )\n -- sem receita o produto vendido é o próprio consumido: o padrão é\n -- a quantidade da linha, e divergir aí seria erro de sistema\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL\n END AS standard_quantity\n ) std ON true;\n\nCOMMENT ON VIEW public.v_inventory_usage_audit IS\n 'O consumo que já saiu do estoque, por linha vendida e produto, ao lado do padrão da receita vigente e da correção que a auditoria lançou. Não cria fila: o razão já sabia tudo isso (001).';\n\nGRANT SELECT ON public.v_inventory_usage_audit TO authenticated;\nGRANT SELECT ON public.v_inventory_usage_audit TO service_role;\n\n-- ── corrigir é lançar a diferença, não reescrever o passado ─────────────────\n--\n-- No V1 \"Corrigir\" e \"Aprovar\" são um ato só porque a baixa ainda não tinha\n-- acontecido. Aqui ela aconteceu, então corrigir para 40 o que saiu como 50\n-- devolve 10 ao saldo — e o razão fica com as duas linhas, que é o que permite\n-- perguntar depois quem corrigiu o quê.\n--\n-- Um motivo é obrigatório, como no V1. Ajuste de estoque sem motivo é o que\n-- transforma uma conferência em um buraco novo.\nCREATE OR REPLACE FUNCTION public.inventory_correct_usage(\n p_item_id uuid,\n p_product_id uuid,\n p_quantity numeric,\n p_reason text\n) RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_reason text := nullif(btrim(p_reason), '');\n v_row record;\n v_delta numeric;\n v_unit uuid;\n v_key text;\n v_op record;\n v_id uuid;\nBEGIN\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: a usage correction needs a reason' USING ERRCODE = '22023';\n END IF;\n IF p_quantity IS NULL OR p_quantity < 0 THEN\n RAISE EXCEPTION 'inventory: the corrected quantity cannot be negative' USING ERRCODE = '22023';\n END IF;\n\n -- o consumido de hoje: a baixa original mais o que auditorias já corrigiram\n SELECT sum(- m.quantity) AS net,\n (array_agg(m.source_location_id ORDER BY m.created_at DESC, m.id DESC))[1] AS location_id,\n (array_agg(m.measurement_unit_id ORDER BY m.created_at DESC, m.id DESC))[1] AS measurement_unit_id,\n (array_agg(m.batch_number ORDER BY m.created_at DESC, m.id DESC))[1] AS batch_number,\n (array_agg(m.expiration_date ORDER BY m.created_at DESC, m.id DESC))[1] AS expiration_date,\n (array_agg(m.unit_cost ORDER BY m.created_at DESC, m.id DESC))[1] AS unit_cost\n INTO v_row\n FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = v_tenant\n AND m.source_item_id = p_item_id\n AND m.product_id = p_product_id\n AND ((m.source_item_type = 'order_item' AND m.kind = 'out')\n OR (m.source_item_type = 'usage_audit' AND m.kind = 'adjust'))\n AND NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id\n );\n\n IF v_row.net IS NULL THEN\n RAISE EXCEPTION 'inventory: no usage of product % on item % to correct', p_product_id, p_item_id\n USING ERRCODE = '22023';\n END IF;\n\n -- positivo devolve ao estoque, negativo tira mais\n v_delta := v_row.net - p_quantity;\n IF v_delta = 0 THEN\n RETURN jsonb_build_object('kind', 'usage_audit', 'status', 'unchanged',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'quantity', p_quantity);\n END IF;\n\n IF v_delta < 0\n AND app.inventory_available(v_tenant, p_product_id, v_row.location_id,\n v_row.batch_number, v_row.expiration_date) < - v_delta THEN\n RAISE EXCEPTION 'inventory: correcting to % would take product % below its available quantity at location %',\n p_quantity, p_product_id, v_row.location_id USING ERRCODE = '23514';\n END IF;\n\n v_unit := app.inventory_authorize_location(v_tenant, v_row.location_id, 'inventory.edit');\n\n -- corrigir duas vezes para o MESMO número é o mesmo ato, e a segunda chamada\n -- devolve o resultado da primeira em vez de mexer no saldo de novo\n v_key := 'usage_audit:' || p_item_id::text || ':' || p_product_id::text || ':' || p_quantity::text;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n v_tenant, 'adjust', v_key,\n jsonb_build_object('source', 'usage_audit', 'item_id', p_item_id,\n 'product_id', p_product_id, 'quantity', p_quantity, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n reason, source_item_type, source_item_id, idempotency_key, line_no,\n operation_id, metadata)\n VALUES\n (v_tenant, p_product_id, 'adjust', v_delta, coalesce(v_row.unit_cost, 0), v_row.location_id,\n v_row.batch_number, v_row.expiration_date, v_row.measurement_unit_id, 'adjustment',\n v_reason, 'usage_audit', p_item_id, v_key, 1, v_op.op_id,\n jsonb_build_object('source', 'usage_audit', 'order_item_id', p_item_id,\n 'posted_quantity', v_row.net, 'corrected_quantity', p_quantity))\n RETURNING id INTO v_id;\n\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, 'adjust', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'usage_audit',\n 'idempotency_key', v_key, 'status', 'corrected',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'location_id', v_row.location_id, 'unit_id', v_unit,\n 'previous_quantity', v_row.net, 'quantity', p_quantity,\n 'delta', v_delta, 'reason', v_reason,\n 'movements', app.inventory_movement_json(v_id)),\n jsonb_build_object('source', 'usage_audit', 'item_id', p_item_id,\n 'product_id', p_product_id, 'unit_id', v_unit,\n 'previous_quantity', v_row.net, 'quantity', p_quantity,\n 'reason', v_reason));\nEND $$;\n\nCOMMENT ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) IS\n 'Corrige o que o atendimento disse ter usado: lança o ajuste da diferença no razão, com motivo, e deixa o rastro ligado à linha vendida por source_item_type=usage_audit (001).';\n\nREVOKE ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) TO service_role;\n`\n\nexport const MIGRATION_002_A_AUDITORIA_FECHA_EM_LOTE = `-- 002_a_auditoria_fecha_em_lote.sql\n--\n-- A AUDITORIA VIRA UMA CONTAGEM. Corrigir linha a linha, cada uma com o seu\n-- motivo, é o desenho de quem conserta UM engano. Quem confere um dia inteiro\n-- desce a lista digitando o que realmente saiu e explica o conjunto UMA vez —\n-- é o mesmo gesto do fechamento de contagem (\\`inventory_close_count_session\\`),\n-- que emite N ajustes sob um motivo só.\n--\n-- POR QUE ISSO PRECISA DE UMA RPC NOVA, E NÃO DE UM LAÇO NO CLIENTE. Um laço\n-- de N chamadas produz N operações, N motivos iguais repetidos e N transações:\n-- a terceira pode falhar depois de as duas primeiras terem gravado, e o\n-- operador fica sem saber o que aplicou. Aqui o lote é UM\n-- \\`plg_inventory_operations\\` — um evento, com as linhas dentro — e o\n-- \\`operation_id\\` de cada movimento é o que devolve o lote inteiro depois.\n--\n-- O QUE **NÃO** MUDA: continua sendo o razão que manda. Aplicar o lote LANÇA a\n-- diferença de cada linha como ajuste; nada é reescrito, nada vira UPDATE de\n-- saldo, e uma linha cuja quantidade não mudou não gera movimento nenhum. Por\n-- isso o rascunho pode viver na tela: não existe segundo lugar guardando a\n-- mesma quantidade, que é o mesmo motivo pelo qual a 001 recusou uma fila.\n\n-- ── uma linha do lote, sem abrir operação própria ───────────────────────────\n--\n-- Extraído de \\`inventory_correct_usage\\` (001) para que o ato de uma linha e o\n-- de um lote sejam literalmente o mesmo código. Não abre nem fecha operação:\n-- quem chama já é dono de uma.\nCREATE OR REPLACE FUNCTION app.inventory_correct_usage_line(\n p_tenant uuid,\n p_op uuid,\n p_key text,\n p_line_no integer,\n p_item_id uuid,\n p_product_id uuid,\n p_quantity numeric,\n p_reason text\n) RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $$\nDECLARE\n v_row record;\n v_delta numeric;\n v_unit uuid;\n v_id uuid;\nBEGIN\n IF p_quantity IS NULL OR p_quantity < 0 THEN\n RAISE EXCEPTION 'inventory: the corrected quantity cannot be negative' USING ERRCODE = '22023';\n END IF;\n\n -- o consumido de hoje: a baixa original mais o que auditorias já corrigiram\n SELECT sum(- m.quantity) AS net,\n (array_agg(m.source_location_id ORDER BY m.created_at DESC, m.id DESC))[1] AS location_id,\n (array_agg(m.measurement_unit_id ORDER BY m.created_at DESC, m.id DESC))[1] AS measurement_unit_id,\n (array_agg(m.batch_number ORDER BY m.created_at DESC, m.id DESC))[1] AS batch_number,\n (array_agg(m.expiration_date ORDER BY m.created_at DESC, m.id DESC))[1] AS expiration_date,\n (array_agg(m.unit_cost ORDER BY m.created_at DESC, m.id DESC))[1] AS unit_cost\n INTO v_row\n FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = p_tenant\n AND m.source_item_id = p_item_id\n AND m.product_id = p_product_id\n AND ((m.source_item_type = 'order_item' AND m.kind = 'out')\n OR (m.source_item_type = 'usage_audit' AND m.kind = 'adjust'))\n AND NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id\n );\n\n IF v_row.net IS NULL THEN\n RAISE EXCEPTION 'inventory: no usage of product % on item % to correct', p_product_id, p_item_id\n USING ERRCODE = '22023';\n END IF;\n\n -- positivo devolve ao estoque, negativo tira mais\n v_delta := v_row.net - p_quantity;\n IF v_delta = 0 THEN\n RETURN jsonb_build_object('status', 'unchanged', 'item_id', p_item_id,\n 'product_id', p_product_id, 'previous_quantity', v_row.net,\n 'quantity', p_quantity, 'delta', 0);\n END IF;\n\n IF v_delta < 0\n AND app.inventory_available(p_tenant, p_product_id, v_row.location_id,\n v_row.batch_number, v_row.expiration_date) < - v_delta THEN\n RAISE EXCEPTION 'inventory: correcting to % would take product % below its available quantity at location %',\n p_quantity, p_product_id, v_row.location_id USING ERRCODE = '23514';\n END IF;\n\n v_unit := app.inventory_authorize_location(p_tenant, v_row.location_id, 'inventory.edit');\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, product_id, kind, quantity, unit_cost, source_location_id,\n batch_number, expiration_date, measurement_unit_id, document_type,\n reason, source_item_type, source_item_id, idempotency_key, line_no,\n operation_id, metadata)\n VALUES\n (p_tenant, p_product_id, 'adjust', v_delta, coalesce(v_row.unit_cost, 0), v_row.location_id,\n v_row.batch_number, v_row.expiration_date, v_row.measurement_unit_id, 'adjustment',\n p_reason, 'usage_audit', p_item_id, p_key, p_line_no, p_op,\n jsonb_build_object('source', 'usage_audit', 'order_item_id', p_item_id,\n 'posted_quantity', v_row.net, 'corrected_quantity', p_quantity))\n RETURNING id INTO v_id;\n\n RETURN jsonb_build_object('status', 'corrected', 'item_id', p_item_id,\n 'product_id', p_product_id, 'location_id', v_row.location_id,\n 'unit_id', v_unit, 'previous_quantity', v_row.net,\n 'quantity', p_quantity, 'delta', v_delta,\n 'movements', app.inventory_movement_json(v_id));\nEND $$;\n\nCOMMENT ON FUNCTION app.inventory_correct_usage_line(uuid, uuid, text, integer, uuid, uuid, numeric, text) IS\n 'Uma linha de correção de consumo dentro de uma operação já aberta: lança a diferença no razão. Compartilhada pela correção avulsa e pelo lote (002).';\n\nREVOKE ALL ON FUNCTION app.inventory_correct_usage_line(uuid, uuid, text, integer, uuid, uuid, numeric, text) FROM PUBLIC;\n\n-- ── a correção avulsa passa a ser um lote de uma linha ──────────────────────\n--\n-- Mesma assinatura, mesma chave de idempotência, mesmo retorno: nada que já\n-- chamava esta função precisa saber que o miolo mudou de casa.\nCREATE OR REPLACE FUNCTION public.inventory_correct_usage(\n p_item_id uuid,\n p_product_id uuid,\n p_quantity numeric,\n p_reason text\n) RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_reason text := nullif(btrim(p_reason), '');\n v_key text;\n v_op record;\n v_line jsonb;\nBEGIN\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: a usage correction needs a reason' USING ERRCODE = '22023';\n END IF;\n\n -- corrigir duas vezes para o MESMO número é o mesmo ato, e a segunda chamada\n -- devolve o resultado da primeira em vez de mexer no saldo de novo\n v_key := 'usage_audit:' || p_item_id::text || ':' || p_product_id::text || ':' || p_quantity::text;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n v_tenant, 'adjust', v_key,\n jsonb_build_object('source', 'usage_audit', 'item_id', p_item_id,\n 'product_id', p_product_id, 'quantity', p_quantity, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n v_line := app.inventory_correct_usage_line(\n v_tenant, v_op.op_id, v_key, 1, p_item_id, p_product_id, p_quantity, v_reason);\n\n IF v_line->>'status' = 'unchanged' THEN\n RETURN jsonb_build_object('kind', 'usage_audit', 'status', 'unchanged',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'quantity', p_quantity);\n END IF;\n\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, 'adjust', v_key,\n jsonb_build_object('operation_id', v_op.op_id, 'kind', 'usage_audit',\n 'idempotency_key', v_key, 'status', 'corrected',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'location_id', v_line->'location_id', 'unit_id', v_line->'unit_id',\n 'previous_quantity', v_line->'previous_quantity',\n 'quantity', p_quantity, 'delta', v_line->'delta', 'reason', v_reason,\n 'movements', v_line->'movements'),\n jsonb_build_object('source', 'usage_audit', 'item_id', p_item_id,\n 'product_id', p_product_id, 'unit_id', v_line->'unit_id',\n 'previous_quantity', v_line->'previous_quantity',\n 'quantity', p_quantity, 'reason', v_reason));\nEND $$;\n\nCOMMENT ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) IS\n 'Corrige o que o atendimento disse ter usado: lança o ajuste da diferença no razão, com motivo, e deixa o rastro ligado à linha vendida por source_item_type=usage_audit (001, reescrita sobre o miolo compartilhado em 002).';\n\nREVOKE ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_correct_usage(uuid, uuid, numeric, text) TO service_role;\n\n-- ── o lote: um motivo, N linhas, UM evento ──────────────────────────────────\n--\n-- \\`p_lines\\` é \\`[{\"item_id\": uuid, \"product_id\": uuid, \"quantity\": numeric}, …]\\`\n-- — a linha vendida, o produto e o que a conferência diz que realmente saiu.\n--\n-- A chave de idempotência sai do CONTEÚDO do lote (linhas ordenadas + motivo),\n-- não de um relógio: reenviar o mesmo lote — o duplo clique, a rede que caiu\n-- entre gravar e responder — devolve o resultado do primeiro envio. E mesmo\n-- sem isso o dano seria zero: a segunda passagem calcula delta 0 e não emite.\nCREATE OR REPLACE FUNCTION public.inventory_correct_usage_batch(\n p_reason text,\n p_lines jsonb\n) RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_reason text := nullif(btrim(p_reason), '');\n v_key text;\n v_op record;\n v_line jsonb;\n v_result jsonb;\n r record;\n v_no integer := 0;\n v_applied integer := 0;\n v_unchanged integer := 0;\n v_lines jsonb := '[]'::jsonb;\n v_movements jsonb := '[]'::jsonb;\nBEGIN\n IF v_reason IS NULL THEN\n RAISE EXCEPTION 'inventory: a usage correction needs a reason' USING ERRCODE = '22023';\n END IF;\n PERFORM app.inventory_check_lines(p_lines);\n\n SELECT 'usage_audit_batch:' || md5(v_reason || '|' || string_agg(\n (l->>'item_id') || ':' || (l->>'product_id') || ':' || (l->>'quantity'), ',' ORDER BY\n (l->>'item_id'), (l->>'product_id')))\n INTO v_key\n FROM jsonb_array_elements(p_lines) AS l;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n v_tenant, 'adjust', v_key,\n jsonb_build_object('source', 'usage_audit_batch', 'reason', v_reason, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n -- a ordem do array é a ordem em que a pessoa digitou, e é ela que o\n -- \\`line_no\\` guarda: reler o lote depois devolve a conferência como ela foi\n -- feita, não reordenada por id\n FOR r IN\n SELECT (l->>'item_id')::uuid AS item_id,\n (l->>'product_id')::uuid AS product_id,\n (l->>'quantity')::numeric AS quantity,\n ord\n FROM jsonb_array_elements(p_lines) WITH ORDINALITY AS t(l, ord)\n ORDER BY ord\n LOOP\n IF r.item_id IS NULL OR r.product_id IS NULL OR r.quantity IS NULL THEN\n RAISE EXCEPTION 'inventory: every audit line needs item_id, product_id and quantity'\n USING ERRCODE = '22023';\n END IF;\n v_no := v_no + 1;\n v_line := app.inventory_correct_usage_line(\n v_tenant, v_op.op_id, v_key, v_no, r.item_id, r.product_id, r.quantity, v_reason);\n IF v_line->>'status' = 'unchanged' THEN\n v_unchanged := v_unchanged + 1;\n ELSE\n v_applied := v_applied + 1;\n v_movements := v_movements || coalesce(v_line->'movements', '[]'::jsonb);\n END IF;\n v_lines := v_lines || jsonb_build_array(v_line - 'movements');\n END LOOP;\n\n v_result := jsonb_build_object(\n 'operation_id', v_op.op_id, 'kind', 'usage_audit_batch',\n 'idempotency_key', v_key, 'status', 'corrected', 'reason', v_reason,\n 'lines_applied', v_applied, 'lines_unchanged', v_unchanged,\n 'lines', v_lines, 'movements', v_movements);\n\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, 'adjust', v_key, v_result,\n jsonb_build_object('source', 'usage_audit_batch', 'reason', v_reason,\n 'lines_applied', v_applied, 'lines_unchanged', v_unchanged));\nEND $$;\n\nCOMMENT ON FUNCTION public.inventory_correct_usage_batch(text, jsonb) IS\n 'Fecha uma conferência de consumo inteira: N linhas corrigidas sob UM motivo e UMA operação, cada diferença lançada como ajuste no razão. O operation_id devolve o lote depois (002).';\n\nREVOKE ALL ON FUNCTION public.inventory_correct_usage_batch(text, jsonb) FROM PUBLIC;\nGRANT ALL ON FUNCTION public.inventory_correct_usage_batch(text, jsonb) TO authenticated;\nGRANT ALL ON FUNCTION public.inventory_correct_usage_batch(text, jsonb) TO service_role;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_the_usage_that_left_stock_can_be_audited\", sql: MIGRATION_001_THE_USAGE_THAT_LEFT_STOCK_CAN_BE_AUDITED },\n { id: \"002_a_auditoria_fecha_em_lote\", sql: MIGRATION_002_A_AUDITORIA_FECHA_EM_LOTE },\n]\n","import React from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { InventoryPage } from './views/InventoryPage'\nimport { createInventoryDashboardWidgets } from './views/dashboardWidgets'\nimport type { ResolvedInventoryConfig } from './context'\nimport type { InventoryDataProvider } from './data/types'\nimport { createMockInventoryProvider } from './data/mock'\nimport { createSupabaseInventoryProvider } from './data/supabase'\nimport { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'\nimport { PluginSettingsPanel } from '@fayz-ai/admin'\nimport { createInventoryStore } from './store'\nimport { inventoryRegistries } from './data/registries'\nimport { inventorySetupGuides } from './lib/setup-guides'\nimport { buildInventoryOnboarding } from './lib/onboarding'\nimport { inventoryLocales } from './locales'\nimport { InventoryGeneralSettings } from './components/InventoryGeneralSettings'\nimport { upsertRecipeTool } from './lib/agent-tools'\nimport { MIGRATIONS } from './migrations'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface InventoryPluginLabels {\n pageTitle: string\n pageSubtitle: string\n dashboard: string\n products: string\n productsNew: string\n productsList: string\n stock: string\n stockEntry: string\n stockExit: string\n stockHistory: string\n recipes: string\n recipesNew: string\n recipesList: string\n}\n\nexport interface InventoryPluginOptions {\n modules?: {\n recipes?: boolean\n stockLocations?: boolean\n batchTracking?: boolean\n /**\n * The product catalogue screens (list + form). Defaults on. Turn OFF when the\n * host already owns product registration elsewhere — an e-commerce app\n * manages products in the shop plugin, and two competing product CRUDs is\n * how the same product ends up entered twice, differently.\n * Stock entry/exit/history stay available either way.\n */\n products?: boolean\n }\n labels?: Partial<InventoryPluginLabels>\n productTypes?: Array<{ value: string; label: string }>\n currency?: { code?: string; locale?: string; symbol?: string }\n navPosition?: number\n navSection?: 'main' | 'secondary'\n scope?: PluginScope\n verticalId?: VerticalId\n dataProvider?: InventoryDataProvider\n locations?: Array<{ id: string; name: string; isHQ?: boolean }>\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: InventoryPluginLabels = {\n pageTitle: 'Inventory',\n pageSubtitle: 'Product catalog and stock management',\n dashboard: 'Dashboard',\n products: 'Products',\n productsNew: 'New',\n productsList: 'List',\n stock: 'Stock',\n stockEntry: 'Entry',\n stockExit: 'Exit',\n stockHistory: 'History',\n recipes: 'Recipes',\n recipesNew: 'New',\n recipesList: 'List',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\nconst DEFAULT_PRODUCT_TYPES = [\n { value: 'ingredient', label: 'Ingredient' },\n { value: 'sale', label: 'For Sale' },\n { value: 'intermediate', label: 'Intermediate' },\n { value: 'asset', label: 'Asset' },\n]\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(options?: InventoryPluginOptions): ResolvedInventoryConfig {\n return {\n modules: {\n products: options?.modules?.products !== false,\n recipes: options?.modules?.recipes !== false,\n stockLocations: options?.modules?.stockLocations !== false,\n batchTracking: options?.modules?.batchTracking ?? false,\n },\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n productTypes: options?.productTypes ?? DEFAULT_PRODUCT_TYPES,\n locations: options?.locations ?? [],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/** The same lazy provider selection used by the plugin, reusable by app composition. */\nexport function createInventoryDataProvider(): InventoryDataProvider {\n return createSafeDataProvider(\n () => createSupabaseInventoryProvider(),\n () => createMockInventoryProvider(),\n )\n}\n\nexport function createInventoryPlugin(options?: InventoryPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n registerTranslations(inventoryLocales)\n const provider = options?.dataProvider ?? createInventoryDataProvider()\n const store = createInventoryStore(provider)\n const dashboardWidgets = createInventoryDashboardWidgets({ config, provider, store })\n\n const PageComponent: React.FC<any> = () =>\n React.createElement(InventoryPage, { config, provider, store, registries: inventoryRegistries })\n\n return {\n id: 'inventory',\n defaultAgentRole: 'operations',\n name: config.labels.pageTitle,\n icon: 'Package',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n // The parts a plan can permit separately (#281, ADR 0025). Counting what\n // you have is the plugin; costing it and forecasting it are what a growing\n // operation pays for.\n facets: [\n { id: 'stock', label: 'Estoque', description: 'Saldo, movimentos e contagem.', includedWithPlugin: true },\n { id: 'costing', label: 'Custo médio e margem', description: 'Custo móvel por lote e a margem que sai dele.' },\n { id: 'purchasing', label: 'Compras e reposição', description: 'Ponto de pedido, sugestão de compra e recebimento.' },\n ],\n dependencies: [],\n // Business effects cross plugin boundaries through the durable event log.\n // Completion consumes the active recipe (or the sold product itself).\n // Cancelled sales never complete, so the app never coordinates a stock effect.\n subscribesTo: [\n {\n event: 'order.completed',\n handler: 'plg_inventory_on_order_completed',\n description: 'A completed Venda consumes its active recipe or the sold product, except the lines a delivery already covered',\n maxAttempts: 5,\n },\n {\n // The delivery is the movement wherever a delivery exists (PRD 05): the\n // quantity comes from the DELIVERY line, so an order of two that\n // delivers one moves the balance by one.\n event: 'fulfillment.completed',\n handler: 'plg_inventory_on_fulfillment_completed',\n description: 'A completed delivery takes its own quantity out of the balance',\n maxAttempts: 5,\n },\n ],\n // The plugin owns ALL of its SQL and says so: what installing it provisions\n // is this list, byte-for-byte the files under src/migrations (embed barrel).\n // Loose SQL was the standing contract violation (DECISIONS 2026-07-06).\n migrations: MIGRATIONS.map((m) => ({\n id: `inventory-${m.id}`,\n version: '1.0.0',\n sql: m.sql,\n description: m.id,\n })),\n declaredFeatures: [\n { id: 'inventory', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ...(config.modules.recipes ? [{ id: 'inventory.recipes', label: config.labels.recipes ?? 'Recipes', group: config.labels.pageTitle }] : []),\n ],\n queryEntities: [\n {\n key: 'inventory:products',\n writable: true,\n entity: {\n name: 'Product',\n namePlural: 'Products',\n icon: 'Package',\n limitKey: 'products',\n permission: { feature: 'inventory', action: 'read' },\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, searchable: true },\n { key: 'kind', label: 'Kind (sale/ingredient/asset)', type: 'text' },\n { key: 'price', label: 'Price', type: 'number' },\n { key: 'cost', label: 'Cost', type: 'number' },\n { key: 'sku', label: 'SKU', type: 'text', searchable: true },\n { key: 'isActive', label: 'Active', type: 'boolean' },\n { key: 'createdAt', label: 'Created at', type: 'text' },\n ],\n data: {\n table: 'products',\n tenantScoped: true,\n archetype: 'product',\n archetypeKind: 'sale',\n searchColumns: ['name', 'sku'],\n defaults: { kind: 'sale', status: 'active', is_active: true },\n },\n },\n },\n ],\n declaredLimits: [\n { key: 'products', label: 'Products', table: 'products' },\n ...(config.modules.recipes ? [{ key: 'recipes', label: config.labels.recipes ?? 'Recipes', table: 'plg_inventory_recipes' }] : []),\n ],\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 4,\n label: config.labels.pageTitle,\n route: '/inventory',\n icon: 'Package',\n permission: { feature: 'inventory', action: 'read' as const },\n },\n ],\n routes: [\n {\n path: '/inventory',\n component: PageComponent,\n permission: { feature: 'inventory', action: 'read' as const },\n // Products live on this hand-built page, not a CRUD route, so nothing\n // would register them and a product the assistant just created would\n // resolve to no page at all.\n entityRoutes: ['product:sale', 'product'],\n },\n ],\n widgets: [],\n dashboardWidgets,\n aiTools: [\n {\n id: 'inventory.low-stock',\n name: 'getLowStock',\n description: 'Lists products with stock below minimum threshold.',\n icon: 'AlertTriangle',\n mode: 'read' as const,\n category: 'Inventory',\n parameters: {\n type: 'object' as const,\n properties: {\n threshold: { type: 'number' as const, description: 'Custom stock threshold' },\n },\n },\n suggestions: [\n { label: 'Which products are running low?' },\n { label: 'What ingredients need restocking?', verticalId: 'food' as const },\n { label: 'Show me a stock summary' },\n { label: 'What are my most used products?' },\n ],\n permission: { feature: 'inventory', action: 'read' as const },\n },\n // `role: 'finance'` is on the tool itself — the plugin defaults to\n // 'operations' and cost per dish belongs to the finance colleague.\n ...(config.modules.recipes ? [upsertRecipeTool] : []),\n ],\n declaredRpcs: [\n ...(config.modules.recipes ? [{\n name: 'agent_inventory_upsert_recipe',\n kind: 'write' as const,\n description:\n 'Guarded recipe upsert: agent_guard (role→plan→recipes cap), ingredient names resolved to products.id inside SQL, unmatched ones returned and stored for the screen to recover, audited.',\n audits: true,\n }] : []),\n ],\n registries: inventoryRegistries,\n settings: [\n {\n id: 'inventory',\n label: 'Inventory',\n icon: 'Package',\n // PluginSettingsPanel, not the toggles component directly. Declaring\n // `registries` does nothing for settings on its own — the panel is the\n // only thing that turns them into screens, which is why Stock Locations,\n // Categories, Units and Suppliers all existed in code and appeared\n // nowhere. financial and crm already render through it.\n component: (() => {\n const Tab: React.FC = () => React.createElement(PluginSettingsPanel, {\n title: config.labels.pageTitle,\n generalSettings: React.createElement(InventoryGeneralSettings),\n registries: inventoryRegistries,\n hostPluginId: 'inventory',\n routeBase: '/settings/inventory',\n })\n Tab.displayName = 'InventorySettingsTab'\n return Tab\n })() as unknown as React.ComponentType<unknown>,\n order: 11,\n permission: { feature: 'inventory', action: 'read' as const },\n },\n ],\n // Como cada tela do Estoque entra em pé — lido pelo assistente.\n onboarding: { program: buildInventoryOnboarding() },\n setupGuides: inventorySetupGuides,\n locales: inventoryLocales,\n }\n}\n\nexport type { InventoryDataProvider } from './data/types'\nexport type { ResolvedInventoryConfig } from './context'\n\n// The movement vocabulary is exported so data importers map onto the same list\n// the UI renders, instead of keeping a private copy that drifts.\nexport {\n MOVEMENT_TYPES,\n MOVEMENT_TYPE_VALUES,\n LEGACY_PT_MOVEMENT_TYPE,\n movementTypeSpec,\n normalizeMovementType,\n} from './lib/movement-vocabulary'\nexport type { MovementTypeSpec } from './lib/movement-vocabulary'\n// O vocabulário só é reusável se o TIPO do verbo vier junto: quem mapeia\n// \"entrada\" para o razão de outro módulo precisa nomear o que recebeu.\nexport type { MovementType } from './types'\nexport type {\n ConsumeRecipeForSourceInput,\n ReverseRecipeConsumptionInput,\n InventoryConsumptionResult,\n InventoryConsumptionStatus,\n InventoryConsumptionSkipReason,\n} from './types'\n"]}
|