@fayz-ai/plugin-inventory 0.18.14 → 0.18.16
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/InventoryGeneralSettings-GTSBWOTS.js +3 -0
- package/dist/InventoryGeneralSettings-GTSBWOTS.js.map +1 -0
- package/dist/InventoryPage-WHNVIP4B.js +6673 -0
- package/dist/InventoryPage-WHNVIP4B.js.map +1 -0
- package/dist/UnitStockLocationsWidget-ZHB4HLRG.js +49 -0
- package/dist/UnitStockLocationsWidget-ZHB4HLRG.js.map +1 -0
- package/dist/chunk-MJZZ4EZB.js +82 -0
- package/dist/chunk-MJZZ4EZB.js.map +1 -0
- package/dist/chunk-UZLEFDCX.js +56 -0
- package/dist/chunk-UZLEFDCX.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2322 -18498
- package/dist/index.js.map +1 -1
- package/dist/migrations/main.browser.js +37 -0
- package/dist/migrations/main.browser.js.map +1 -0
- package/dist/migrations/main.js +9363 -0
- package/dist/migrations/main.js.map +1 -0
- package/package.json +11 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/views/DashboardView.tsx","../src/views/ProductStockTab.tsx","../src/views/ProductBarcodesTab.tsx","../src/views/ProductVariantsTab.tsx","../src/views/productFichas.ts","../src/views/productEntity.tsx","../src/views/ProductListView.tsx","../src/components/InventoryGeneralSettings.tsx","../src/views/useHasMenu.ts","../src/lib/recipe-units.ts","../src/views/recipe/shared.tsx","../src/views/recipe/IngredientCostDialog.tsx","../src/views/recipe/RecipeAiDialog.tsx","../src/views/recipe/TransformIntermediateDialog.tsx","../src/views/recipe/QuickIngredientDialog.tsx","../src/views/recipe/printRecipe.ts","../src/views/recipe/RecipeEditor.tsx","../src/views/ProductRecipeTab.tsx","../src/views/ProductComplementsTab.tsx","../src/views/recipe/GenerateImageDialog.tsx","../src/views/ProductDetailView.tsx","../src/views/ProductCrudForm.tsx","../src/views/StockMovementView.tsx","../src/views/MovementHistoryView.tsx","../src/views/StockPanelView.tsx","../src/views/StockCountsView.tsx","../src/views/StockCountFormView.tsx","../src/views/StockCountSessionView.tsx","../src/lib/agent-tools.ts","../src/views/recipe/exportRecipesXlsx.ts","../src/views/recipe/SelectProductDialog.tsx","../src/views/RecipesView.tsx","../src/views/UsageAuditView.tsx","../src/views/GapScreens.tsx","../src/components/InventoryOnboarding.tsx","../src/views/InventoryPage.tsx","../src/views/UnitStockLocationsWidget.tsx","../src/views/dashboardWidgets.tsx","../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","movements","useTranslation","useState","useCallback","useEffect","toast","jsxs","Button","Plus","ConfirmDialog","Card","CardContent","Input","key","qty","hasMinimum","T","products","useMemo","React","formatCurrency","useRef","Modal","ModalContent","ModalHeader","ModalTitle","ModalBody","Loader2","ModalFooter","AiActionButton","ModalDescription","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","num","TooltipProvider","Tooltip","TooltipTrigger","TooltipContent","Package","Trash2","Skeleton","seq","norm","Switch","CurrencyInput","Sparkles","X","Upload","errorMessage","createIdempotencyKey","SubpageHeader","MOVEMENT_TYPES","createPendingCommand","t","SearchSelect","Fragment","Check","signedQuantity","ArrowDownRight","ArrowUpRight","RefreshCw","ArrowRightLeft","movementTypeSpec","Field","FilterPanel","FilterPanelField","RequiredFilter","FilterMenuRow","DatePicker","Boxes","CircleDashed","MapPin","Layers","DataTable","CrudListView","Textarea","SegmentedControl","Search","cmvPercent","CMV_TONE","cmvBand","Printer","Pencil","CMV_GOOD_THRESHOLD","CMV_ALERT_THRESHOLD","CountedField","summarizeCount","Badge","ListView","ComingSoon","activeFacet","RECORD_GROUP","recordRailFields","AlertTriangle","ctx","PRODUCT_CATEGORY_KIND","stockLocationEntity","PluginSettingsPanel"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;AAAA;;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;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;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAwRhD,IAAM,+CAAA,GAAkD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAqKxD,IAAM,4CAAA,GAA+C,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,CAAA;AAwLrD,IAAM,mDAAA,GAAsD,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,CAAA;AA4E5D,IAAM,4CAAA,GAA+C,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,CAAA;AAyUrD,IAAM,kCAAA,GAAqC,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,CAAA;AAiM3C,IAAM,qDAAA,GAAwD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AA4B9D,IAAM,uDAAA,GAA0D,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,CAAA;AA8KhE,IAAM,0CAAA,GAA6C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AA8anD,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAwgBjD,IAAM,sEAAA,GAAyE,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,CAAA;AAqR/E,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAqQzD,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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+PlD,IAAM,6CAAA,GAAgD,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,CAAA;AA6PtD,IAAM,4CAAA,GAA+C,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,CAAA;AAsQrD,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;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;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;AA8KvD,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,CAAA;AAuP9C,IAAM,oCAAA,GAAuC,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,CAAA;AA4L7C,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;AAAA;AAAA;AAAA;AAAA;AAAA;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;AA0T/D,IAAM,sCAAA,GAAyC,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,CAAA;AAwI/C,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,CAAA;AAmFxD,IAAM,gDAAA,GAAmD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,CAAA;AAsBzD,IAAM,kDAAA,GAAqD,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,CAAA;AAyD3D,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;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAkTlD,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;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","file":"index.js","sourcesContent":["import type React from 'react'\nimport type { DetailTab } from '@fayz-ai/core'\nimport { createPluginContext, formatCurrency, type CurrencyConfig } from '@fayz-ai/admin'\nimport type { InventoryPluginLabels } from './index'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { InventoryUIState } from '@fayz-ai/inventory/store'\nimport type { StockMovement } from '@fayz-ai/inventory/domain/movement'\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 * Chave de tradução do rótulo, quando ele é do PRODUTO e não do app.\n *\n * Sem isto, a lista de uma casa brasileira mostrava «For Sale» e\n * «Ingredient» na coluna Classificação: o padrão é uma literal inglesa\n * escrita no manifesto, e só os apps que a sobrescreveram escapavam.\n * Quando há chave, ela vence; o rótulo do app continua ganhando quando ele\n * declara o seu.\n */\n labelKey?: string\n}\n\nexport interface LocationOption {\n id: string\n name: string\n isHQ?: boolean\n}\n\nexport interface ResolvedInventoryConfig {\n /** Ver `InventoryPluginOptions.moduleNav`. */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\n modules: InventoryModules\n labels: InventoryPluginLabels\n currency: InventoryCurrency\n productTypes: ProductTypeOption[]\n locations: LocationOption[]\n /** Tabs contributed to the product record. See `InventoryPluginOptions.productDetailTabs`. */\n productDetailTabs: DetailTab[]\n /** Telas emprestadas por outro plugin. Ver `InventoryPluginOptions.extraViews`. */\n extraViews: Array<{\n id: string\n label: string\n icon?: string\n render: () => React.ReactNode\n children?: Array<{ id: string; label: string; render: () => React.ReactNode }>\n defaultChildLabel?: string\n }>\n /**\n * O documento que originou um movimento, DENTRO DE UM MODAL — como no V1.\n *\n * Recebe o movimento (tem `documentType` e `operationId`) e devolve o conteúdo\n * do modal, ou `undefined` quando não há documento para abrir. O Estoque desenha\n * a moldura e cuida do abrir/fechar; quem sabe o que é uma NF-e é o outro\n * plugin.\n *\n * Era uma ROTA, e rota tira a pessoa da lista: ela estava percorrendo o razão,\n * clicava no motivo e perdia o lugar. O V1 abre em modal, e é o certo — o\n * documento é uma consulta, não um destino.\n */\n documentModal?: (movement: StockMovement, close: () => void) => React.ReactNode\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","import React, { useCallback, useEffect, useMemo, useRef, 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 { createPendingCommand, useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport type { Product } from '@fayz-ai/inventory/domain/product'\nimport {\n MOVEMENT_TYPES, movementTypeSpec, type CreateStockMovementInput, type StockMovement,\n} from '@fayz-ai/inventory/domain/movement'\nimport { hasMinimum, type StockPosition } from '@fayz-ai/inventory/domain/stock'\nimport { createIdempotencyKey } from '@fayz-ai/inventory/lib/idempotency'\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 const command = useRef(createPendingCommand<CreateStockMovementInput>(() => createIdempotencyKey('inventory:product-movement'), (input) => input.productId))\n const [pending, setPending] = 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 if (command.current.running) return\n setSaving(true)\n setPending(true)\n try {\n await command.current.run({\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 }, (input) => provider.createMovement(input))\n setEntryVerb(null)\n try {\n await load()\n onChanged?.()\n } catch {\n toast.warning(t('inventory.stock.refreshAfterCommit'))\n }\n } catch (error) {\n toast.error(t('inventory.productDetail.movementFailed'), {\n description: (error as Error).message,\n })\n } finally {\n setSaving(false)\n setPending(command.current.pending)\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 {hasMinimum(item.minQuantity) && (\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.productDetail.minimum')}: <span className=\"font-medium text-foreground tabular-nums\">{item.minQuantity}</span>\n </p>\n )}\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={(verb) => { if (!command.current.pending) setEntryVerb(verb) }}\n onClose={() => { if (!command.current.pending) 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 readOnly={pending}\n notice={pending ? t('inventory.stock.pendingRetry') : undefined}\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, { useCallback, useEffect, useState } from 'react'\nimport { Star, Trash2, Plus } from 'lucide-react'\nimport {\n Button, Card, CardContent, ConfirmDialog, Input, toast,\n Select, SelectTrigger, SelectValue, SelectContent, SelectItem,\n Tooltip, TooltipTrigger, TooltipContent, TooltipProvider,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { Product, ProductBarcode } from '@fayz-ai/inventory/domain/product'\n\n// ---------------------------------------------------------------------------\n// Códigos de Barras — a aba que o V1 mostra em TODO produto já salvo.\n//\n// Um código só não serve ao balcão: a mesma mercadoria chega em embalagem de\n// 500 ml e de 1 L, com códigos diferentes, e quem bipa não escolhe qual. O\n// PRINCIPAL é o que a etiqueta imprime, e é único por produto — o banco\n// garante com índice, a tela mostra com a estrela.\n// ---------------------------------------------------------------------------\n\nconst TYPES = ['EAN-13', 'EAN-8', 'UPC-A', 'CODE-128', 'CODE-39', 'DUN-14', 'Interno']\n\nfunction RowSkeleton() {\n return (\n <div className=\"space-y-2\">\n {[1, 2].map((i) => <div key={i} className=\"h-10 rounded bg-muted/30 animate-pulse\" />)}\n </div>\n )\n}\n\nexport function ProductBarcodesTab({ item }: { item: Product }) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const productId = item?.id\n\n const [rows, setRows] = useState<ProductBarcode[] | null>(null)\n const [code, setCode] = useState('')\n const [type, setType] = useState(TYPES[0])\n const [description, setDescription] = useState('')\n const [saving, setSaving] = useState(false)\n const [removing, setRemoving] = useState<ProductBarcode | null>(null)\n\n const load = useCallback(async () => {\n if (!productId || !provider.getProductBarcodes) { setRows([]); return }\n setRows(await provider.getProductBarcodes(productId))\n }, [productId, provider])\n\n useEffect(() => { void load() }, [load])\n\n // Sem o provider a aba não promete o que não entrega.\n if (!provider.addProductBarcode) {\n return (\n <Card>\n <CardContent className=\"p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.barcodes.unavailable')}</p>\n </CardContent>\n </Card>\n )\n }\n\n async function add() {\n const value = code.trim()\n if (!value || !productId) return\n // O mesmo código em dois produtos é uma venda errada no balcão, e o banco\n // recusa com índice único — a mensagem tem de dizer isso, não \"erro\".\n if ((rows ?? []).some((r) => r.barcode === value)) {\n toast.error(t('inventory.barcodes.duplicate'))\n return\n }\n setSaving(true)\n try {\n await provider.addProductBarcode!(productId, { barcode: value, barcodeType: type, description })\n setCode(''); setDescription('')\n await load()\n } catch (error) {\n toast.error(t('inventory.barcodes.duplicate'), { description: String((error as Error)?.message ?? '') })\n } finally {\n setSaving(false)\n }\n }\n\n async function makePrimary(row: ProductBarcode) {\n if (!productId || !row.id || row.isPrimary) return\n await provider.setPrimaryProductBarcode?.(productId, row.id)\n await load()\n }\n\n async function remove() {\n const row = removing\n setRemoving(null)\n if (!row?.id) return\n await provider.removeProductBarcode?.(row.id)\n await load()\n }\n\n return (\n // Não há `TooltipProvider` global: cada consumidor embrulha o seu.\n <TooltipProvider delayDuration={300}>\n <div className=\"space-y-5\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"fz-fields fz-fields-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium\">{t('inventory.barcodes.code')}</label>\n <Input\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder={t('inventory.barcodes.codePlaceholder')}\n // Um leitor de código de barras digita e manda Enter. Sem isto a\n // pessoa bipa, nada acontece, e ela procura o botão com o leitor\n // na mão.\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); void add() } }}\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium\">{t('inventory.barcodes.type')}</label>\n <Select value={type} onValueChange={setType}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {TYPES.map((v) => <SelectItem key={v} value={v}>{v}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium\">{t('inventory.barcodes.description')}</label>\n <Input\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={t('inventory.barcodes.descriptionPlaceholder')}\n />\n </div>\n </div>\n <div className=\"mt-3 flex justify-end\">\n {/* Ação bloqueada DIZ o que falta, em vez de um botão morto. */}\n <Tooltip>\n <TooltipTrigger asChild>\n <span>\n <Button onClick={() => void add()} disabled={!code.trim() || saving}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('common.add')}\n </Button>\n </span>\n </TooltipTrigger>\n {!code.trim() && <TooltipContent>{t('inventory.barcodes.needCode')}</TooltipContent>}\n </Tooltip>\n </div>\n </CardContent>\n </Card>\n\n {rows === null && <RowSkeleton />}\n\n {rows !== null && rows.length === 0 && (\n <Card>\n <CardContent className=\"p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.barcodes.empty')}</p>\n </CardContent>\n </Card>\n )}\n\n {rows !== null && rows.length > 0 && (\n <Card>\n <CardContent className=\"p-0\">\n <ul className=\"divide-y\">\n {rows.map((row) => (\n <li key={row.id} className=\"flex items-center gap-3 px-4 py-3\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n aria-label={row.isPrimary ? t('inventory.barcodes.isPrimary') : t('inventory.barcodes.makePrimary')}\n onClick={() => void makePrimary(row)}\n className=\"shrink-0 rounded p-1 hover:bg-muted\"\n >\n <Star className={`h-4 w-4 ${row.isPrimary ? 'fill-primary text-primary' : 'text-muted-foreground'}`} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n {row.isPrimary ? t('inventory.barcodes.isPrimary') : t('inventory.barcodes.makePrimary')}\n </TooltipContent>\n </Tooltip>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-mono text-sm\">{row.barcode}</p>\n {(row.description || row.barcodeType) && (\n <p className=\"truncate text-xs text-muted-foreground\">\n {[row.barcodeType, row.description].filter(Boolean).join(' · ')}\n </p>\n )}\n </div>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n aria-label={t('common.delete')}\n onClick={() => setRemoving(row)}\n className=\"shrink-0 rounded p-1 text-muted-foreground hover:bg-muted hover:text-destructive\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('common.delete')}</TooltipContent>\n </Tooltip>\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n )}\n\n <ConfirmDialog\n open={!!removing}\n onCancel={() => setRemoving(null)}\n title={t('inventory.barcodes.removeTitle')}\n description={removing?.barcode}\n confirmLabel={t('common.delete')}\n variant=\"destructive\"\n onConfirm={() => void remove()}\n />\n </div>\n </TooltipProvider>\n )\n}\n","import React, { useCallback, useEffect, useState } from 'react'\nimport { Plus } from 'lucide-react'\nimport { Badge, Button, Card, CardContent, Input, Skeleton, Switch, toast } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { Product, ProductVariant } from '@fayz-ai/inventory/domain/product'\n\n// Same shape as the loaded list (name, count, switch), so nothing jumps when the rows arrive.\nfunction ListSkeleton() {\n return (\n <Card>\n <CardContent className=\"p-0\">\n <ul className=\"divide-y\" aria-busy=\"true\">\n {[28, 16, 20].map((width, i) => (\n <li key={i} className=\"flex items-center gap-3 px-4 py-3\">\n <Skeleton className=\"h-4\" style={{ width: `${width}%` }} />\n <span className=\"flex-1\" />\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-5 w-9 rounded-full\" />\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n )\n}\n\n/** Sizes and colours of one product. Each keeps its own stock balance; cost stays on the product. */\nexport function ProductVariantsTab({ item }: { item: Product }) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const productId = item?.id\n\n const [rows, setRows] = useState<ProductVariant[] | null>(null)\n const [name, setName] = useState('')\n const [sku, setSku] = useState('')\n const [saving, setSaving] = useState(false)\n\n const load = useCallback(async () => {\n if (!productId || !provider.getProductVariants) { setRows([]); return }\n // A failed read must not leave the skeleton up forever.\n try {\n setRows(await provider.getProductVariants(productId))\n } catch (error) {\n setRows([])\n toast.error(t('inventory.variants.loadFailed'), { description: String((error as Error)?.message ?? '') })\n }\n }, [productId, provider, t])\n\n useEffect(() => { void load() }, [load])\n\n if (!provider.addProductVariant) {\n return (\n <Card>\n <CardContent className=\"p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.variants.unavailable')}</p>\n </CardContent>\n </Card>\n )\n }\n\n async function add() {\n const value = name.trim()\n if (!value || !productId) return\n if ((rows ?? []).some((r) => r.name.trim().toLowerCase() === value.toLowerCase())) {\n toast.error(t('inventory.variants.duplicate'))\n return\n }\n setSaving(true)\n try {\n await provider.addProductVariant!(productId, { name: value, sku })\n setName(''); setSku('')\n await load()\n } catch (error) {\n toast.error(t('inventory.variants.saveFailed'), { description: String((error as Error)?.message ?? '') })\n } finally {\n setSaving(false)\n }\n }\n\n async function toggle(row: ProductVariant, active: boolean) {\n setRows((prev) => (prev ?? []).map((r) => (r.id === row.id ? { ...r, isActive: active } : r)))\n try {\n await provider.setProductVariantActive?.(row.id, active)\n } catch (error) {\n toast.error(t('inventory.variants.saveFailed'), { description: String((error as Error)?.message ?? '') })\n await load()\n }\n }\n\n // The default variant stands in for a product with no sizes. Once it has\n // real ones it is only worth a row while stock still sits on it.\n const sized = (rows ?? []).some((r) => !r.isDefault)\n const shown = (rows ?? []).filter((r) => !r.isDefault || !sized || r.onHand !== 0)\n\n return (\n <div className=\"space-y-5\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"fz-fields fz-fields-3\">\n <div>\n <label className=\"mb-1 block text-xs font-medium\">{t('inventory.variants.name')}</label>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t('inventory.variants.namePlaceholder')}\n onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); void add() } }}\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium\">{t('inventory.variants.sku')}</label>\n <Input value={sku} onChange={(e) => setSku(e.target.value)} placeholder={t('inventory.variants.skuPlaceholder')} />\n </div>\n <div className=\"flex items-end justify-end\">\n <Button onClick={() => void add()} disabled={!name.trim() || saving}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n {t('common.add')}\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {rows === null && <ListSkeleton />}\n\n {rows !== null && shown.length === 0 && (\n <Card>\n <CardContent className=\"p-8 text-center\">\n <p className=\"text-xs text-muted-foreground\">{t('inventory.variants.empty')}</p>\n </CardContent>\n </Card>\n )}\n\n {rows !== null && shown.length > 0 && (\n <Card>\n <CardContent className=\"p-0\">\n <ul className=\"divide-y\">\n {shown.map((row) => (\n <li key={row.id} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <p className={`flex items-center gap-2 text-sm font-medium ${row.isActive ? '' : 'text-muted-foreground line-through'}`}>\n <span className=\"truncate\">{row.name}</span>\n {row.isDefault && row.name.trim() !== t('inventory.variants.default') && (\n <Badge variant=\"secondary\" className=\"shrink-0\">{t('inventory.variants.default')}</Badge>\n )}\n </p>\n {row.sku && <p className=\"truncate font-mono text-xs text-muted-foreground\">{row.sku}</p>}\n </div>\n <span className=\"shrink-0 text-sm tabular-nums text-muted-foreground\">\n {t('inventory.variants.onHand', { count: row.onHand.toLocaleString('pt-BR') })}\n </span>\n <Switch checked={row.isActive} onCheckedChange={(v) => void toggle(row, v)} aria-label={t('common.active')} />\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n )}\n </div>\n )\n}\n","import type { FieldDef, FieldGroup } from '@fayz-ai/core'\nimport type { InventoryCurrency } from '../context'\nimport { T } from '@fayz-ai/inventory/data/tables'\n\n// ---------------------------------------------------------------------------\n// As FICHAS do produto — as abas que nascem de um interruptor.\n//\n// Cada interruptor da Classificação abre uma ABA, como no V1 e com o mesmo\n// nome. A condição mora em `visibleWhen`, campo a campo: quando todos os\n// campos de um grupo se escondem, o grupo não se desenha (`FormGroup` devolve\n// `null`) e a aba inteira some junto, porque `CrudFormPage` não oferece aba\n// vazia — um rótulo que o clique não cumpre é pior que rótulo nenhum.\n//\n// Os vocabulários fiscais são os do V1, valor por valor — um CST ou um CFOP\n// que não bata com o da nota é uma nota rejeitada na SEFAZ, não um rótulo\n// diferente.\n// ---------------------------------------------------------------------------\n\ntype T9n = (key: string, params?: Record<string, string | number>) => string\n\nconst yes = (key: string) => (vals: Record<string, unknown>) => vals[key] === true\n\n/** Os canais do V1. Texto livre no banco: cada praça tem o seu aplicativo. */\nexport const SALE_CHANNELS = [\n { key: 'counter', label: 'Balcão' },\n { key: 'delivery', label: 'Delivery Próprio' },\n { key: 'ifood', label: 'iFood' },\n { key: '99food', label: '99Food' },\n { key: 'keeta', label: 'Keeta' },\n] as const\n\nexport const channelFieldKey = (channel: string) => `saleChannel_${channel}`\n\nconst ICMS_ORIGINS = [\n { value: '0', label: '0 — Nacional' },\n { value: '1', label: '1 — Estrangeira (importação direta)' },\n { value: '2', label: '2 — Estrangeira (adquirida no mercado interno)' },\n { value: '3', label: '3 — Nacional com conteúdo de importação > 40%' },\n { value: '4', label: '4 — Nacional (processos produtivos básicos)' },\n { value: '5', label: '5 — Nacional com conteúdo de importação ≤ 40%' },\n { value: '6', label: '6 — Estrangeira (importação direta, sem similar)' },\n { value: '7', label: '7 — Estrangeira (adquirida internamente, sem similar)' },\n { value: '8', label: '8 — Nacional com conteúdo de importação > 70%' },\n]\n\nconst CST_OPTIONS = [\n { value: '00', label: '00 — Tributada integralmente' },\n { value: '10', label: '10 — Tributada com cobrança de ICMS por ST' },\n { value: '20', label: '20 — Com redução de base de cálculo' },\n { value: '30', label: '30 — Isenta/não tributada com cobrança de ICMS por ST' },\n { value: '40', label: '40 — Isenta' },\n { value: '41', label: '41 — Não tributada' },\n { value: '50', label: '50 — Suspensão' },\n { value: '51', label: '51 — Diferimento' },\n { value: '60', label: '60 — ICMS cobrado anteriormente por ST' },\n { value: '70', label: '70 — Com redução de BC e cobrança de ICMS por ST' },\n { value: '90', label: '90 — Outras' },\n]\n\nconst CFOP_OPTIONS = [\n { value: '5101', label: '5101 — Venda de produção do estabelecimento' },\n { value: '5102', label: '5102 — Venda de mercadoria adquirida' },\n { value: '5103', label: '5103 — Venda de produção, efetuada fora do estabelecimento' },\n { value: '5104', label: '5104 — Venda de mercadoria adquirida, efetuada fora do estabelecimento' },\n { value: '5405', label: '5405 — Venda de mercadoria adquirida com ST' },\n { value: '5949', label: '5949 — Outra saída não especificada' },\n { value: '6101', label: '6101 — Venda de produção (interestadual)' },\n { value: '6102', label: '6102 — Venda de mercadoria adquirida (interestadual)' },\n]\n\nconst PIS_COFINS_OPTIONS = [\n { value: '01', label: '01 — Operação tributável (alíquota normal)' },\n { value: '02', label: '02 — Operação tributável (alíquota diferenciada)' },\n { value: '04', label: '04 — Operação tributável (ST)' },\n { value: '05', label: '05 — Operação tributável (alíquota por unidade)' },\n { value: '06', label: '06 — Operação tributável (alíquota zero)' },\n { value: '07', label: '07 — Operação isenta da contribuição' },\n { value: '08', label: '08 — Operação sem incidência da contribuição' },\n { value: '09', label: '09 — Operação com suspensão da contribuição' },\n { value: '49', label: '49 — Outras operações de saída' },\n { value: '99', label: '99 — Outras operações' },\n]\n\nconst BASE_CALC_OPTIONS = [\n { value: '0', label: '0 — Margem de Valor Agregado (%)' },\n { value: '1', label: '1 — Pauta (valor)' },\n { value: '2', label: '2 — Preço tabelado máximo (valor)' },\n { value: '3', label: '3 — Valor da operação' },\n]\n\nconst ASSET_STATUS_OPTIONS = [\n { value: 'active', label: 'Ativo' },\n { value: 'maintenance', label: 'Em manutenção' },\n { value: 'disposed', label: 'Baixado' },\n { value: 'lost', label: 'Extraviado' },\n]\n\n/**\n * Os sete interruptores e as duas travas de entrada — a seção que decide quais\n * outras existem. Fica numa coluna só porque cada linha é um interruptor com\n * uma explicação, e três por linha espremem a explicação a ponto de ela sumir.\n */\nexport function classificationFields(t: T9n, currency: InventoryCurrency, hasRecipes = true): FieldDef[] {\n const flag = (key: string, label: string, hint: string): FieldDef => ({\n key, label, hint, type: 'boolean', group: 'classification', defaultValue: false, showInTable: false,\n })\n return [\n flag('isIngredient', t('inventory.productForm.flagIngredient'), t('inventory.productForm.flagIngredientHint')),\n flag('isForSale', t('inventory.productForm.flagForSale'), t('inventory.productForm.flagForSaleHint')),\n ...(hasRecipes ? [flag('isIntermediate', t('inventory.productForm.flagIntermediate'), t('inventory.productForm.flagIntermediateHint'))] : []),\n flag('isAsset', t('inventory.productForm.flagAsset'), t('inventory.productForm.flagAssetHint')),\n ...(hasRecipes ? [flag('isProduced', t('inventory.productForm.flagProduced'), t('inventory.productForm.flagProducedHint'))] : []),\n flag('isResale', t('inventory.productForm.flagResale'), t('inventory.productForm.flagResaleHint')),\n flag('trackByUnitLabel', t('inventory.productForm.flagTracked'), t('inventory.productForm.flagTrackedHint')),\n\n {\n key: 'professionalResalePrice', label: t('inventory.productForm.professionalResalePrice'), type: 'currency',\n group: 'classification', showInTable: false,\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n hint: t('inventory.productForm.professionalResalePriceHint'),\n visibleWhen: yes('isResale'),\n },\n\n // A trava vale para QUALQUER produto — revenda também tem lote e validade.\n // No V1 ela vivia escondida na aba Insumo e estava ligada em zero dos 221\n // produtos ativos: a trava existia e ninguém a encontrava.\n flag('requireBatchForStock', t('inventory.productForm.requireBatch'), t('inventory.productForm.requireBatchHint')),\n flag('requireExpiryForStock', t('inventory.productForm.requireExpiry'), t('inventory.productForm.requireExpiryHint')),\n ]\n}\n\n/** Embalagem e conversões — como a casa compra versus como ela conta. */\nexport function packagingFields(t: T9n): FieldDef[] {\n return [\n {\n key: 'contentPerUnit', label: t('inventory.productForm.contentPerUnit'), type: 'number',\n group: 'packaging', min: 0, placeholder: '300', showInTable: false,\n hint: t('inventory.productForm.contentPerUnitHint'),\n },\n {\n key: 'contentUnitId', label: t('inventory.productForm.contentUnit'), type: 'relation',\n group: 'packaging', relation: { table: T.measurementUnits, labelField: 'abbreviation' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'purchaseUnitId', label: t('inventory.productForm.purchaseUnit'), type: 'relation',\n group: 'packaging', relation: { table: T.measurementUnits, labelField: 'abbreviation' },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'conversionFactor', label: t('inventory.productForm.conversionFactor'), type: 'number',\n group: 'packaging', min: 0, placeholder: '1', showInTable: false,\n hint: t('inventory.productForm.conversionFactorHint'),\n },\n ]\n}\n\n/** A ficha do insumo: o que a COMPRA precisa saber. */\nexport function ingredientFields(t: T9n): FieldDef[] {\n const when = yes('isIngredient')\n return [\n {\n key: 'ingReorderPoint', label: t('inventory.productForm.ingReorderPoint'), type: 'number', group: 'ingredient', min: 0,\n // O mínimo é o que não se pode furar; este é o aviso que ainda chega a\n // tempo de comprar. Sem a frase, os dois campos parecem o mesmo.\n hint: t('inventory.productForm.ingReorderPointHint'),\n placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false,\n },\n { key: 'ingLeadTimeDays', label: t('inventory.productForm.ingLeadTime'), type: 'number', group: 'ingredient', min: 0, placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false },\n { key: 'ingShelfLifeDays', label: t('inventory.productForm.ingShelfLife'), type: 'number', group: 'ingredient', min: 0, placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false },\n { key: 'ingStorageTemperature', label: t('inventory.productForm.ingStorageTemp'), type: 'text', group: 'ingredient', placeholder: '2°C a 8°C', visibleWhen: when, showInTable: false },\n { key: 'ingNotes', label: t('inventory.productForm.notes'), type: 'textarea', group: 'ingredient', span: 2, visibleWhen: when, showInTable: false },\n ]\n}\n\n/** A ficha de venda: o que o cardápio e o balcão precisam saber. */\nexport function saleFields(t: T9n, currency: InventoryCurrency): FieldDef[] {\n const when = yes('isForSale')\n const channels: FieldDef[] = SALE_CHANNELS.map((ch) => ({\n key: channelFieldKey(ch.key),\n label: ch.label,\n type: 'currency',\n group: 'saleChannels',\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n visibleWhen: when,\n showInTable: false,\n }))\n return [\n { key: 'salePreparationTime', label: t('inventory.productForm.salePrepTime'), type: 'number', group: 'sale', min: 0, placeholder: '15', visibleWhen: when, showInTable: false },\n { key: 'saleServesQuantity', label: t('inventory.productForm.saleServes'), type: 'number', group: 'sale', min: 0, placeholder: '2', visibleWhen: when, showInTable: false },\n { key: 'saleCalories', label: t('inventory.productForm.saleCalories'), type: 'number', group: 'sale', min: 0, placeholder: '350', visibleWhen: when, showInTable: false },\n { key: 'saleMenuDescription', label: t('inventory.productForm.saleMenuDescription'), type: 'textarea', group: 'sale', span: 2, visibleWhen: when, showInTable: false },\n { key: 'saleAllergens', label: t('inventory.productForm.saleAllergens'), type: 'text', group: 'sale', span: 2, placeholder: t('inventory.productForm.saleAllergensPlaceholder'), visibleWhen: when, showInTable: false },\n { key: 'saleSoldByWeight', label: t('inventory.productForm.saleSoldByWeight'), type: 'boolean', group: 'sale', visibleWhen: when, showInTable: false },\n { key: 'saleHighlightDelivery', label: t('inventory.productForm.saleHighlightDelivery'), type: 'boolean', group: 'sale', visibleWhen: when, showInTable: false },\n { key: 'saleAvailableForDelivery', label: t('inventory.productForm.saleAvailableDelivery'), type: 'boolean', group: 'sale', defaultValue: true, visibleWhen: when, showInTable: false },\n { key: 'saleAvailableForCounter', label: t('inventory.productForm.saleAvailableCounter'), type: 'boolean', group: 'sale', defaultValue: true, visibleWhen: when, showInTable: false },\n { key: 'saleNotes', label: t('inventory.productForm.notes'), type: 'textarea', group: 'sale', span: 2, visibleWhen: when, showInTable: false },\n ...channels,\n ]\n}\n\nexport function intermediateFields(t: T9n): FieldDef[] {\n const when = yes('isIntermediate')\n return [\n { key: 'intYieldPercentage', label: t('inventory.productForm.intYield'), type: 'number', group: 'intermediate', min: 0, max: 100, placeholder: '85', visibleWhen: when, showInTable: false },\n { key: 'intPreparationTime', label: t('inventory.productForm.intPrepTime'), type: 'number', group: 'intermediate', min: 0, placeholder: '30', visibleWhen: when, showInTable: false },\n { key: 'intShelfLifeHours', label: t('inventory.productForm.intShelfLifeHours'), type: 'number', group: 'intermediate', min: 0, placeholder: '48', visibleWhen: when, showInTable: false },\n { key: 'intBatchSize', label: t('inventory.productForm.intBatchSize'), type: 'number', group: 'intermediate', min: 0, placeholder: '5', visibleWhen: when, showInTable: false },\n {\n key: 'intBatchUnitId', label: t('inventory.productForm.intBatchUnit'), type: 'relation', group: 'intermediate',\n relation: { table: T.measurementUnits, labelField: 'abbreviation' },\n placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false,\n },\n { key: 'intStorageInstructions', label: t('inventory.productForm.intStorage'), type: 'textarea', group: 'intermediate', span: 2, visibleWhen: when, showInTable: false },\n { key: 'intNotes', label: t('inventory.productForm.notes'), type: 'textarea', group: 'intermediate', span: 2, visibleWhen: when, showInTable: false },\n ]\n}\n\nexport function assetFields(t: T9n, currency: InventoryCurrency): FieldDef[] {\n const when = yes('isAsset')\n const money = (key: string, label: string): FieldDef => ({\n key, label, type: 'currency', group: 'asset',\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n visibleWhen: when, showInTable: false,\n })\n return [\n money('assetValue', t('inventory.productForm.assetValue')),\n money('assetResidualValue', t('inventory.productForm.assetResidualValue')),\n { key: 'assetUsefulLifeMonths', label: t('inventory.productForm.assetUsefulLife'), type: 'number', group: 'asset', min: 0, placeholder: '60', visibleWhen: when, showInTable: false },\n { key: 'assetDepreciationRate', label: t('inventory.productForm.assetDepreciation'), type: 'number', group: 'asset', min: 0, max: 100, placeholder: '20', visibleWhen: when, showInTable: false },\n { key: 'assetSerialNumber', label: t('inventory.productForm.assetSerial'), type: 'text', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetAcquisitionDate', label: t('inventory.productForm.assetAcquisition'), type: 'date', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetWarrantyExpiryDate', label: t('inventory.productForm.assetWarranty'), type: 'date', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetStatus', label: t('inventory.productForm.assetStatus'), type: 'select', group: 'asset', options: ASSET_STATUS_OPTIONS, defaultValue: 'active', visibleWhen: when, showInTable: false },\n { key: 'assetLocation', label: t('inventory.productForm.assetLocation'), type: 'text', group: 'asset', placeholder: t('inventory.productForm.assetLocationPlaceholder'), visibleWhen: when, showInTable: false },\n {\n // Responsável é uma PESSOA do cadastro, não um nome digitado: é quem\n // responde pelo equipamento quando ele some.\n key: 'assetResponsiblePersonId', label: t('inventory.productForm.assetResponsible'), type: 'relation', group: 'asset',\n relation: { table: 'people', labelField: 'name' },\n placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false,\n },\n { key: 'assetInsurancePolicy', label: t('inventory.productForm.assetInsurance'), type: 'text', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetLastMaintenanceDate', label: t('inventory.productForm.assetLastMaintenance'), type: 'date', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetNextMaintenanceDate', label: t('inventory.productForm.assetNextMaintenance'), type: 'date', group: 'asset', visibleWhen: when, showInTable: false },\n { key: 'assetNotes', label: t('inventory.productForm.notes'), type: 'textarea', group: 'asset', span: 2, visibleWhen: when, showInTable: false },\n ]\n}\n\n/**\n * A ficha fiscal. Só existe para o que se vende — comprar não emite nota, e\n * pedir NCM de um insumo que nunca sai da casa é campo para ninguém preencher.\n */\nexport function taxFields(t: T9n): FieldDef[] {\n const when = yes('isForSale')\n return [\n {\n key: 'taxGroupId', label: t('inventory.productForm.taxGroup'), type: 'relation', group: 'tax', span: 2,\n relation: { table: 'plg_fiscalbr_tax_groups', labelField: 'name' },\n hint: t('inventory.productForm.taxGroupHint'),\n placeholder: t('inventory.productForm.optional'), visibleWhen: when, showInTable: false,\n },\n { key: 'taxNcm', label: 'NCM', type: 'text', group: 'tax', placeholder: '33059000', hint: t('inventory.productForm.ncmHint'), visibleWhen: when, showInTable: false },\n { key: 'taxCest', label: 'CEST', type: 'text', group: 'tax', placeholder: '0300100', visibleWhen: when, showInTable: false },\n { key: 'taxIcmsOrigin', label: t('inventory.productForm.icmsOrigin'), type: 'select', group: 'tax', options: ICMS_ORIGINS, visibleWhen: when, showInTable: false },\n { key: 'taxIcmsRate', label: t('inventory.productForm.icmsRate'), type: 'number', group: 'tax', min: 0, max: 100, visibleWhen: when, showInTable: false },\n { key: 'taxCfop', label: 'CFOP', type: 'select', group: 'tax', options: CFOP_OPTIONS, visibleWhen: when, showInTable: false },\n { key: 'taxCst', label: 'CST', type: 'select', group: 'tax', options: CST_OPTIONS, hint: t('inventory.productForm.cstHint'), visibleWhen: when, showInTable: false },\n { key: 'taxPisSituation', label: 'PIS', type: 'select', group: 'tax', options: PIS_COFINS_OPTIONS, visibleWhen: when, showInTable: false },\n { key: 'taxPisRate', label: t('inventory.productForm.pisRate'), type: 'number', group: 'tax', min: 0, max: 100, visibleWhen: when, showInTable: false },\n { key: 'taxCofinsSituation', label: 'COFINS', type: 'select', group: 'tax', options: PIS_COFINS_OPTIONS, visibleWhen: when, showInTable: false },\n { key: 'taxCofinsRate', label: t('inventory.productForm.cofinsRate'), type: 'number', group: 'tax', min: 0, max: 100, visibleWhen: when, showInTable: false },\n { key: 'taxBaseCalculationMode', label: t('inventory.productForm.baseCalcMode'), type: 'select', group: 'tax', options: BASE_CALC_OPTIONS, visibleWhen: when, showInTable: false },\n { key: 'taxBenefitCode', label: t('inventory.productForm.benefitCode'), type: 'text', group: 'tax', visibleWhen: when, showInTable: false },\n { key: 'taxPovertyFundRate', label: t('inventory.productForm.povertyFund'), type: 'number', group: 'tax', min: 0, max: 100, visibleWhen: when, showInTable: false },\n // A reforma já está no cadastro do V1 e vem junto: deixar de fora\n // obrigaria a recadastrar o catálogo no dia em que IBS e CBS valerem.\n { key: 'taxIbsCbsSituation', label: t('inventory.productForm.ibsCbsSituation'), type: 'text', group: 'tax', placeholder: '200 — Alíquota reduzida', visibleWhen: when, showInTable: false },\n { key: 'taxIbsCbsClassification', label: t('inventory.productForm.ibsCbsClassification'), type: 'text', group: 'tax', placeholder: '200034 — Fornecimento de alimentos', visibleWhen: when, showInTable: false },\n ]\n}\n\n/**\n * As fichas em ABAS, como no V1 — e com os mesmos nomes.\n *\n * O cadastro do produto tem dez assuntos. Empilhados numa rolagem só, quem veio\n * trocar o preço percorre noventa campos; é por isso que o V1 usa abas, e a\n * aba é parte do fluxo, não enfeite. Uma aba cujo interruptor está desligado\n * não é desenhada (todos os campos somem por `visibleWhen`, e `CrudFormPage`\n * não oferece aba vazia).\n */\nexport function fichaGroups(t: T9n): FieldGroup[] {\n const ing = t('inventory.productForm.ingredientSection')\n const sale = t('inventory.productForm.saleSection')\n const inter = t('inventory.productForm.intermediateSection')\n const asset = t('inventory.productForm.assetSection')\n const tax = t('inventory.productForm.taxSection')\n return [\n // Embalagem fica nos Dados Gerais, como no V1: é como a casa COMPRA a\n // mesma coisa, não outro assunto.\n { id: 'packaging', label: t('inventory.productForm.packaging'), description: t('inventory.productForm.packagingDesc'), columns: 2 },\n\n // Os ícones vêm do ICON_MAP; nome fora dele cai para a casinha em silêncio.\n { id: 'ingredient', tab: ing, tabIcon: 'Wheat', label: ing, description: t('inventory.productForm.ingredientSectionDesc'), columns: 2 },\n { id: 'sale', tab: sale, tabIcon: 'ShoppingCart', label: sale, description: t('inventory.productForm.saleSectionDesc'), columns: 2 },\n { id: 'saleChannels', tab: sale, label: t('inventory.productForm.saleChannelsSection'), description: t('inventory.productForm.saleChannelsSectionDesc'), columns: 3 },\n { id: 'tax', tab: tax, tabIcon: 'Receipt', label: tax, description: t('inventory.productForm.taxSectionDesc'), columns: 2 },\n { id: 'intermediate', tab: inter, tabIcon: 'Workflow', label: inter, description: t('inventory.productForm.intermediateSectionDesc'), columns: 2 },\n { id: 'asset', tab: asset, tabIcon: 'Wrench', label: asset, description: t('inventory.productForm.assetSectionDesc'), columns: 2 },\n ]\n}\n\n// ---------------------------------------------------------------------------\n// O formulário genérico trabalha com um registro PLANO; o produto, no domínio,\n// é um tronco com fichas (insumo, venda, intermediário, patrimônio, fiscal).\n// A tradução entre os dois mora aqui, nas duas direções, e em lugar nenhum\n// mais: a entidade declara os campos, o provider grava as tabelas, e esta é a\n// única peça que sabe que `ingReorderPoint` e\n// `plg_inventory_product_ingredient_info.reorder_point` são a mesma coisa.\n//\n// Os prefixos (`ing`, `sale`, `int`, `asset`, `tax`) existem porque quatro\n// fichas têm um campo chamado «observações» e três têm «tempo de preparo».\n// ---------------------------------------------------------------------------\n\n/** Prefixo → chaves da ficha. A ordem das chaves é a da ficha no domínio. */\nexport const FICHA_KEYS = {\n ingredientInfo: {\n prefix: 'ing',\n // No minimum/maximum here: the stock minimum is the general one\n // (product_settings), the only one alerts and restock read.\n keys: ['reorderPoint', 'leadTimeDays', 'shelfLifeDays', 'storageTemperature', 'notes'],\n },\n saleInfo: {\n prefix: 'sale',\n keys: ['menuDescription', 'allergens', 'preparationTimeMinutes', 'servesQuantity',\n 'calories', 'soldByWeight', 'highlightDelivery', 'availableForDelivery',\n 'availableForCounter', 'notes'],\n },\n intermediateInfo: {\n prefix: 'int',\n keys: ['yieldPercentage', 'preparationTimeMinutes', 'shelfLifeHours', 'batchSize',\n 'batchUnitId', 'storageInstructions', 'notes'],\n },\n assetInfo: {\n prefix: 'asset',\n keys: ['assetValue', 'residualValue', 'usefulLifeMonths', 'depreciationRate',\n 'serialNumber', 'acquisitionDate', 'warrantyExpiryDate', 'assetStatus',\n 'assetLocation', 'responsiblePersonId', 'insurancePolicy',\n 'lastMaintenanceDate', 'nextMaintenanceDate', 'notes'],\n },\n taxInfo: {\n prefix: 'tax',\n keys: ['taxGroupId', 'ncm', 'cest', 'icmsOrigin', 'icmsRate', 'cfop', 'cst',\n 'pisSituation', 'pisRate', 'cofinsSituation', 'cofinsRate',\n 'baseCalculationMode', 'benefitCode', 'povertyFundRate',\n 'ibsCbsSituation', 'ibsCbsClassification'],\n },\n} as const\n\nexport type FichaName = keyof typeof FICHA_KEYS\n\n/**\n * `assetValue` com prefixo `asset` viraria `assetAssetValue`. Quando a chave\n * do domínio já começa pelo prefixo, ela mantém o próprio nome — é o que a\n * entidade declara e é como a pessoa lê na tela.\n */\nexport function flatKey(prefix: string, key: string): string {\n if (key.startsWith(prefix)) return key\n return prefix + key.charAt(0).toUpperCase() + key.slice(1)\n}\n\nconst EMPTY_CLASSIFICATION = {\n isIngredient: false, isForSale: false, isIntermediate: false, isAsset: false,\n isProduced: false, isResale: false, trackByUnitLabel: false,\n}\n\n/** Produto (com fichas) → o registro PLANO que as telas leem. */\nexport function flattenProduct(p: Record<string, any>): Record<string, any> {\n const values: Record<string, any> = {\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 purchaseUnitId: p.purchaseUnitId ?? '',\n conversionFactor: p.conversionFactor ?? 1,\n ...EMPTY_CLASSIFICATION,\n ...(p.classification ?? {}),\n }\n\n const e = p.extras ?? {}\n values.commissionPercent = e.commissionPercent ?? 0\n values.chartAccountId = e.chartAccountId ?? ''\n values.contentPerUnit = e.contentPerUnit ?? ''\n values.contentUnitId = e.contentUnitId ?? ''\n values.avgPurchasePrice = e.avgPurchasePrice ?? 0\n values.professionalResalePrice = e.professionalResalePrice ?? 0\n values.requireBatchForStock = e.requireBatchForStock ?? false\n values.requireExpiryForStock = e.requireExpiryForStock ?? false\n\n for (const name of Object.keys(FICHA_KEYS) as FichaName[]) {\n const { prefix, keys } = FICHA_KEYS[name]\n const ficha = p[name] ?? {}\n for (const key of keys) values[flatKey(prefix, key)] = (ficha as Record<string, any>)[key] ?? ''\n }\n\n for (const ch of SALE_CHANNELS) {\n const found = (p.saleChannels ?? []).find((c: { channel: string }) => c.channel === ch.key)\n values[channelFieldKey(ch.key)] = found?.price ?? ''\n }\n return values\n}\n\n\nconst num = (v: unknown): number | undefined => {\n if (v === '' || v == null) return undefined\n const n = Number(v)\n return Number.isFinite(n) ? n : undefined\n}\nconst str = (v: unknown): string | undefined => {\n const s = typeof v === 'string' ? v.trim() : v == null ? '' : String(v)\n return s === '' ? undefined : s\n}\n\n/**\n * Valores planos → as fichas do produto.\n *\n * Uma ficha só é enviada quando o interruptor dela está LIGADO: desligar\n * «Patrimônio» esconde a seção e não apaga o valor do equipamento — o dado\n * volta inteiro se o interruptor voltar. É o que o V1 faz, e apagar valor de\n * patrimônio por causa de um clique seria perda silenciosa.\n */\nexport function toFichas(values: Record<string, any>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n const enabled: Record<FichaName, boolean> = {\n ingredientInfo: values.isIngredient === true,\n saleInfo: values.isForSale === true,\n intermediateInfo: values.isIntermediate === true,\n assetInfo: values.isAsset === true,\n taxInfo: values.isForSale === true,\n }\n // Campos que são número no domínio. O resto viaja como texto.\n const numeric = new Set([\n 'reorderPoint', 'leadTimeDays', 'shelfLifeDays',\n 'preparationTimeMinutes', 'servesQuantity', 'calories',\n 'yieldPercentage', 'shelfLifeHours', 'batchSize',\n 'assetValue', 'residualValue', 'usefulLifeMonths', 'depreciationRate',\n 'icmsRate', 'pisRate', 'cofinsRate', 'povertyFundRate',\n ])\n const boolean = new Set(['soldByWeight', 'highlightDelivery', 'availableForDelivery', 'availableForCounter'])\n\n for (const name of Object.keys(FICHA_KEYS) as FichaName[]) {\n if (!enabled[name]) continue\n const { prefix, keys } = FICHA_KEYS[name]\n // A sheet this house never drew (the sale sheet with no menu) carries no\n // key at all; a boolean read as `false` would otherwise write a row.\n if (!keys.some((key) => flatKey(prefix, key) in values)) continue\n const ficha: Record<string, unknown> = {}\n for (const key of keys) {\n const raw = values[flatKey(prefix, key)]\n if (boolean.has(key)) ficha[key] = raw === true\n else if (numeric.has(key)) ficha[key] = num(raw)\n else ficha[key] = str(raw)\n }\n // Ficha em que NADA foi respondido não vira linha. É o caso da fiscal\n // numa casa sem o plugin fiscal: a seção não foi desenhada, então não há\n // valor nenhum, e gravar uma linha vazia só criaria dado que ninguém pediu\n // numa tabela que talvez nem exista.\n if (Object.values(ficha).every((v) => v === undefined)) continue\n out[name] = ficha\n }\n\n if (enabled.saleInfo) {\n const channels = SALE_CHANNELS\n .map((ch) => ({ channel: ch.key as string, price: num(values[channelFieldKey(ch.key)]) }))\n // Canal sem preço não vira linha: zero gravado afirmaria «de graça neste\n // canal», e vazio quer dizer «usa o preço base».\n .filter((c): c is { channel: string; price: number } => c.price != null && c.price > 0)\n if (channels.length) out.saleChannels = channels\n }\n return out\n}\n\n\n/**\n * O caminho de volta: valores planos → o que o provider grava.\n *\n * Recebe o registro INTEIRO (o plano atual com as alterações por cima), e não\n * só os campos encostados: uma ficha é gravada como linha completa, então\n * mandar meia ficha apagaria o resto dela em silêncio.\n */\nexport function unflattenProduct(values: Record<string, any>): Record<string, unknown> {\n const classification = {\n isIngredient: values.isIngredient === true,\n isForSale: values.isForSale === true,\n isIntermediate: values.isIntermediate === true,\n isAsset: values.isAsset === true,\n isProduced: values.isProduced === true,\n isResale: values.isResale === true,\n trackByUnitLabel: values.trackByUnitLabel === true,\n }\n const patch: Record<string, unknown> = {\n classification,\n extras: {\n commissionPercent: Number(values.commissionPercent) || 0,\n chartAccountId: values.chartAccountId ?? '',\n contentPerUnit: values.contentPerUnit === '' ? undefined : Number(values.contentPerUnit) || undefined,\n contentUnitId: values.contentUnitId ?? '',\n avgPurchasePrice: Number(values.avgPurchasePrice) || undefined,\n professionalResalePrice: Number(values.professionalResalePrice) || undefined,\n requireBatchForStock: values.requireBatchForStock === true,\n requireExpiryForStock: values.requireExpiryForStock === true,\n },\n ...toFichas(values),\n }\n // Os campos do tronco só viajam quando vieram: `undefined` deixa o valor\n // anterior onde está, e '' é uma resposta («limpei isto»).\n const trunk = ['name', 'sku', 'barcode', 'brand', 'description', 'costPrice', 'salePrice',\n 'minQuantity', 'maxQuantity', 'categoryId', 'measurementUnitId', 'supplierId',\n 'defaultLocationId', 'purchaseUnitId', 'conversionFactor', 'isActive'] as const\n for (const key of trunk) {\n if (values[key] !== undefined) patch[key] = values[key]\n }\n return patch\n}\n","import React from 'react'\nimport type { EntityDef, EntityImageConfig, FieldDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\nimport { Thumbnail } from '@fayz-ai/ui'\nimport { Package } from 'lucide-react'\nimport { formatCurrency, type InventoryCurrency, type ProductTypeOption } from '../context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport { PRODUCT_CATEGORY_KIND, T } from '@fayz-ai/inventory/data/tables'\nimport { hasMinimum, isLowStock, isOutOfStock } from '@fayz-ai/inventory/domain/stock'\nimport { marginPercent, stockValue } from '@fayz-ai/inventory/domain/product'\nimport { ProductStockTab } from './ProductStockTab'\nimport { ProductBarcodesTab } from './ProductBarcodesTab'\nimport { ProductVariantsTab } from './ProductVariantsTab'\nimport {\n classificationFields, packagingFields, ingredientFields, saleFields,\n intermediateFields, assetFields, taxFields, fichaGroups,\n} from './productFichas'\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\n// Same switches ProductCrudForm requires at least one of.\nconst CLASSIFICATION_KEYS = ['isIngredient', 'isForSale', 'isIntermediate', 'isAsset', 'isProduced', 'isResale', 'trackByUnitLabel']\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 /**\n * Esta casa emite nota? Liga a ficha de tributos — e vem LIGADA, como no V1,\n * onde Fiscal aparece em todo produto de venda.\n *\n * A ficha mora numa tabela do plugin fiscal (`plg_fiscalbr_product_tax_info`,\n * migration 011 dele), aplicada no cluster. Um app que não emite nota passa\n * `false` e os dezesseis campos somem — oferecer campo que o banco não tem\n * onde guardar é pior do que não oferecer nenhum.\n */\n hasFiscal = true,\n /** False for a house with no menu: the sale sheet is menu and counter data, not shelf data. */\n hasMenu = true,\n /** False where the house switched technical sheets off: nothing here is produced. */\n hasRecipes = true,\n): EntityDef {\n // O rótulo traduzido vence a literal do manifesto — ver ProductTypeOption.\n const typeName = (pt: ProductTypeOption) => (pt.labelKey ? t(pt.labelKey) : pt.label)\n const typeOptions = productTypes.map((pt) => ({\n label: typeName(pt),\n value: pt.value,\n description: TYPE_DESCRIPTION_KEYS[pt.value] ? t(TYPE_DESCRIPTION_KEYS[pt.value]) : undefined,\n }))\n const typeLabel = (v: unknown) => {\n const found = productTypes.find((p) => p.value === v)\n return found ? typeName(found) : String(v ?? '')\n }\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 // A foto vem junto do nome, como na lista da loja. O produto de um\n // estoque é uma COISA, e a pessoa que confere a prateleira reconhece a\n // embalagem antes de ler o SKU. `imageUrl` já viajava na linha — só não\n // tinha quem o desenhasse.\n //\n // O quadrado aparece SEMPRE, com foto ou sem: um produto sem imagem\n // que não renderizasse nada puxaria o nome para trás contra as linhas\n // que têm, e a coluna deixaria de ler como coluna.\n <div className=\"flex items-center gap-3\">\n <Thumbnail src={row.imageUrl} icon={Package} />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <p className={`truncate 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 </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 key: 'commissionPercent', label: t('inventory.productForm.commissionPercent'), type: 'number',\n group: 'general', min: 0, max: 100, placeholder: '0', showInTable: false,\n hint: t('inventory.productForm.commissionPercentHint'),\n },\n {\n // Conta de DESPESA: é por ela que a compra deste produto entra no\n // resultado. Sem chave estrangeira no banco porque a casa pode não ter\n // o financeiro instalado — aqui o campo some junto com a tabela.\n key: 'chartAccountId', label: t('inventory.productForm.chartAccount'), type: 'relation',\n group: 'general', relation: { table: 'plg_financial_chart_of_accounts', labelFields: ['code', 'name'] },\n placeholder: t('inventory.productForm.optional'), showInTable: false,\n },\n {\n key: 'avgPurchasePrice', label: t('inventory.productForm.avgPurchasePrice'), type: 'currency',\n group: 'general', currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n hint: t('inventory.productForm.avgPurchasePriceHint'), showInTable: false,\n },\n\n // — Classification (form: segmented) + Type column (table: badge) —\n // O TIPO continua existindo como coluna e como faceta da lista, mas não é\n // mais pergunta do formulário: ele é DERIVADO dos sete interruptores da\n // Classificação. Perguntar as duas coisas deixaria a tela aceitar um\n // produto marcado «Venda» cuja única ficha é a de insumo.\n {\n key: 'productType', label: t('inventory.productForm.classification'), type: 'segmented',\n options: typeOptions,\n showInForm: false, showInTable: true, sortable: false,\n renderCell: (v, row: any) => {\n // Produto sem NENHUM interruptor ligado não é «Venda» — é um produto\n // que ninguém classificou. Dizer «Venda» aqui era a resposta padrão de\n // um campo vazio, e ela explicava mal por que a ficha não abre aba\n // nenhuma: 1.369 dos 3.334 produtos deste cluster vieram assim de uma\n // importação que não trouxe o tipo.\n const c = row?.classification\n const unset = c && !c.isIngredient && !c.isForSale && !c.isIntermediate && !c.isAsset\n if (unset) {\n return (\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium bg-muted/50 text-muted-foreground italic\">\n {t('inventory.productForm.classificationUnset')}\n </span>\n )\n }\n return (\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\n // Balance and minimum share one cell; the alarm is the summary's `isLowStock`, so a product without a minimum never turns red.\n {\n key: 'currentQuantity', label: t('inventory.productList.stock'), type: 'number',\n showInForm: false, showInTable: true, sortable: true,\n renderCell: (_v, row: any) => {\n const qty = Number(row.currentQuantity) || 0\n const min = Number(row.minQuantity) || 0\n const unit = row.measurementUnitName\n const below = isLowStock(qty, min)\n const empty = isOutOfStock(qty)\n return (\n <span className=\"block text-right\">\n <span className={below ? 'font-medium text-destructive' : empty ? 'text-muted-foreground' : ''}>\n {qty.toLocaleString('pt-BR', { maximumFractionDigits: 3 })}\n {unit ? <span className=\"ml-1 text-xs text-muted-foreground\">{unit}</span> : null}\n </span>\n {/* Sem mínimo não há de que estar abaixo, e escrever \"mín. 0\"\n sugeriria que há. O convite fica no painel, uma vez, em vez de\n repetido em cada uma das 169 linhas. */}\n {hasMinimum(min) && (\n <span className=\"block text-xs text-muted-foreground\">\n mín. {min.toLocaleString('pt-BR', { maximumFractionDigits: 3 })}\n </span>\n )}\n </span>\n )\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 // Mesma regra do preço de venda: custo zero é \"não cadastrado\", não\n // \"custa nada\". E é ele que faz o Valor abaixo mentir.\n renderCell: (v) => {\n const n = Number(v)\n return (\n <span className=\"block text-right text-muted-foreground\">\n {v == null || v === '' || !Number.isFinite(n) || n === 0 ? '—' : formatCurrency(n, currency)}\n </span>\n )\n },\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 const value = stockValue(row.currentQuantity, row.costPrice)\n if (value === null) {\n return (\n <span className=\"block text-right text-muted-foreground\" title=\"Sem custo cadastrado, o valor deste saldo não pode ser calculado\">\n —\n </span>\n )\n }\n return <span className=\"block text-right font-medium\">{formatCurrency(value, 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 // O V1 mostra Custo E Venda lado a lado. Custo sozinho não responde\n // \"quanto isto rende\", e o preço estava só dentro da ficha.\n showInTable: true,\n // Zero aqui é \"não informado\", não \"de graça\" — 100 dos 169 produtos deste\n // tenant estão assim. \"R$ 0,00\" afirmaria um preço; o travessão diz que\n // falta cadastrar, que é a verdade e é o que se pode agir sobre.\n renderCell: (v) => {\n const n = Number(v)\n return (\n <span className=\"block text-right text-muted-foreground\">\n {v == null || v === '' || !Number.isFinite(n) || n === 0 ? '—' : formatCurrency(n, currency)}\n </span>\n )\n },\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.isForSale === true,\n },\n {\n key: 'margin', label: t('inventory.productForm.margin'), type: 'computed', group: 'pricing', showInTable: false,\n visibleWhen: (vals) => vals.isForSale === true,\n compute: (vals) => {\n const m = marginPercent(Number(vals.salePrice), Number(vals.costPrice))\n if (m === null) return null\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: {\n table: T.productCategories, labelField: 'name', filter: { kind: PRODUCT_CATEGORY_KIND },\n create: { permission: { feature: 'inventory', action: 'edit' } },\n },\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 // Opening stock: asked once, while creating, and written as an ordinary\n // entry movement after the product exists (ProductCrudForm).\n {\n key: '_initialQty', label: t('inventory.productForm.initialQuantity'), type: 'number', group: 'initialEntry',\n min: 0, placeholder: '0', showInTable: false, showInDetail: false,\n },\n {\n key: '_initialLocationId', label: t('inventory.productForm.initialLocation'), type: 'relation', group: 'initialEntry',\n relation: { table: T.stockLocations, labelField: 'name' },\n hint: t('inventory.productForm.initialLocationHint'),\n placeholder: t('inventory.productForm.optional'), showInTable: false, showInDetail: false,\n visibleWhen: (v) => Number(v._initialQty) > 0,\n },\n {\n key: '_initialUnitCost', label: t('inventory.productForm.initialUnitCost'), type: 'currency', group: 'initialEntry',\n currency: currency.code, currencySymbol: currency.symbol, currencyLocale: currency.locale,\n hint: t('inventory.productForm.initialUnitCostHint'), showInTable: false, showInDetail: false,\n visibleWhen: (v) => Number(v._initialQty) > 0,\n },\n {\n key: '_initialBatch', label: t('inventory.productForm.initialBatch'), type: 'text', group: 'initialEntry',\n required: true, showInTable: false, showInDetail: false,\n visibleWhen: (v) => Number(v._initialQty) > 0 && v.requireBatchForStock === true,\n },\n {\n key: '_initialExpiry', label: t('inventory.productForm.initialExpiry'), type: 'date', group: 'initialEntry',\n required: true, showInTable: false, showInDetail: false,\n visibleWhen: (v) => Number(v._initialQty) > 0 && v.requireExpiryForStock === true,\n },\n // O rail de todo cadastro. `isActive` já era LIDO na lista (a linha\n // aparece esmaecida) e não tinha campo: dava para ver que um produto\n // estava inativo e não dava para reativá-lo.\n ...recordRailFields({ tagsTable: 'products', activeLabel: t('common.active') }),\n\n // As fichas: cada uma nasce de um interruptor da Classificação e some\n // junto com ele. A ordem aqui é a ordem das abas do V1.\n ...packagingFields(t),\n ...classificationFields(t, currency, hasRecipes),\n ...ingredientFields(t),\n ...(hasMenu ? saleFields(t, currency) : []),\n ...(hasRecipes ? intermediateFields(t) : []),\n ...assetFields(t, currency),\n ...(hasFiscal ? taxFields(t) : []),\n ]\n\n return {\n name: t('inventory.stock.product'),\n namePlural: t('inventory.nav.products'),\n icon: 'Package',\n displayField: 'name',\n // General data in the main column, situation (unit, tags, active) beside it.\n formColumns: 2,\n // MOSTRAR e TROCAR são coisas diferentes. `image` só existe quando há\n // provider, porque é ele que sabe enviar o arquivo — mas sem `imageField` a\n // página do produto ficava sem foto mesmo com a foto na linha, enquanto a\n // lista a desenhava. O campo responde por desenhar; `image`, por substituir.\n imageField: 'imageUrl',\n image: provider?.uploadProductImage ? productImage(provider) : undefined,\n fields,\n // A primeira aba é a dos Dados Gerais, na ordem do V1: o que a coisa é,\n // como ela é embalada, o que ela SERVE (a Classificação), preço, estoque e\n // organização. Cada ficha depois disso tem aba própria — é assim no V1, e\n // dez assuntos numa rolagem só fazem quem veio trocar o preço percorrer\n // noventa campos.\n fieldGroups: (() => {\n const fichas = fichaGroups(t)\n const ficha = (id: string) => fichas.find((g) => g.id === id)!\n // Wizard steps for a new product; the ficha groups step by their tab.\n const identity = t('inventory.productForm.stepIdentity')\n const stock = t('inventory.productForm.stepStock')\n return [\n { id: 'general', step: identity, tabIcon: 'Package', label: t('inventory.productForm.generalInfo'), columns: 2 as const, imageSlot: true },\n { ...ficha('packaging'), step: identity },\n {\n id: 'classification', step: t('inventory.productForm.stepClassification'), tabIcon: 'Tags', label: t('inventory.productForm.classification'), description: t('inventory.productForm.classificationDesc'), columns: 2 as const,\n validate: (v: Record<string, unknown>) => (CLASSIFICATION_KEYS.some((k) => v[k] === true) ? null : t('inventory.productForm.classificationRequired')),\n },\n { id: 'pricing', step: t('inventory.productForm.stepPricing'), tabIcon: 'DollarSign', label: t('inventory.productForm.pricing'), columns: 3 as const },\n { id: 'stock', step: stock, tabIcon: 'Warehouse', label: t('inventory.productForm.stockLevels'), description: t('inventory.productForm.stockLevelsDesc'), columns: 2 as const },\n { id: 'organization', step: stock, label: t('inventory.productForm.organization'), description: t('inventory.productForm.organizationDesc'), columns: 2 as const },\n // Daqui em diante é UMA ABA cada, na ordem do V1: Insumo · Venda ·\n // Fiscal · Intermediário · Patrimônio. A aba só aparece com o\n // interruptor dela ligado.\n ficha('ingredient'),\n ...(hasMenu ? [ficha('sale'), ficha('saleChannels')] : []),\n ...(hasFiscal ? [ficha('tax')] : []),\n ...(hasRecipes ? [ficha('intermediate')] : []),\n ficha('asset'),\n {\n id: 'initialEntry', step: t('inventory.productForm.stepInitialEntry'), tabIcon: 'PackageCheck', createOnly: true,\n label: t('inventory.productForm.initialEntrySection'), description: t('inventory.productForm.initialEntrySectionDesc'), columns: 2 as const,\n },\n { ...RECORD_GROUP, step: identity },\n ]\n })(),\n // Duas facetas: o TIPO (o que a coisa é) e a SITUAÇÃO (se vale). A\n // segunda abre em «Ativos», como toda lista de cadastro.\n facets: [\n { field: 'productType', allLabel: t('crud.list.allFacet') },\n activeFacet({ active: t('common.active'), inactive: t('common.inactive'), all: t('crud.list.allFacet') }),\n ],\n detailTabs: [\n // Aparece em TODO produto, como no V1: o código é do produto, não do\n // tipo dele, e é por ele que o balcão acha a mercadoria.\n {\n id: 'barcodes',\n label: t('inventory.barcodes.tab'),\n // `Barcode` NÃO está no ICON_MAP e cairia para a casinha em silêncio.\n icon: 'ScanLine',\n component: ProductBarcodesTab as never,\n },\n {\n id: 'variants',\n label: t('inventory.variants.tab'),\n icon: 'Layers',\n component: ProductVariantsTab as never,\n },\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, Boxes, Layers } from 'lucide-react'\nimport { CrudListView, usePermissionOptional, type CrudBulkAction } from '@fayz-ai/admin'\nimport { toast, FilterMenuRow, FilterPanel, FilterPanelField, RequiredFilter } from '@fayz-ai/ui'\nimport { useInventoryConfig, useInventoryProvider, useInventoryStore } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { Product, ProductCategory, ProductType } from '@fayz-ai/inventory/domain/product'\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 // CATEGORIA: o recorte que o V1 tem e esta lista nao tinha. `categoryId` ja\n // existia na consulta do provider — faltava quem o pedisse.\n const [categoryId, setCategoryId] = useState('')\n const [categories, setCategories] = useState<ProductCategory[]>([])\n useEffect(() => {\n let vivo = true\n provider.getCategories().then((rows) => { if (vivo) setCategories(rows) }).catch(() => {})\n return () => { vivo = false }\n }, [provider])\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 // ── O RASCUNHO E O RECORTE EM VIGOR ──────────────────────────────────────\n //\n // O V1 monta esta tela como formulario: tipo, categoria, unidade, busca e um\n // «Filtrar» no fim — e nao recarrega a cada campo. Num catalogo de rede cada\n // troca aqui e uma pagina inteira relida do banco.\n const rascunho = useMemo(\n () => ({ productType: typeFilter, categoryId, isActive: activeFilter }),\n [typeFilter, categoryId, activeFilter],\n )\n const [emVigor, setEmVigor] = useState(rascunho)\n const filtrosPendentes = useMemo(\n () => JSON.stringify(rascunho) !== JSON.stringify(emVigor),\n [rascunho, emVigor],\n )\n const aplicarFiltros = useCallback(() => {\n setPage(1)\n setEmVigor(() => rascunho)\n }, [rascunho])\n const limparFiltros = () => {\n setTypeFilter(undefined)\n setCategoryId('')\n setActiveFilter(undefined)\n }\n const filtrosAtivos =\n (typeFilter ? 1 : 0) + (categoryId ? 1 : 0) + (activeFilter !== undefined ? 1 : 0)\n\n const query = useMemo(() => ({\n productType: emVigor.productType as ProductType | undefined,\n categoryId: emVigor.categoryId || undefined,\n search: search || undefined,\n isActive: emVigor.isActive === undefined ? undefined : emVigor.isActive === 'true',\n page,\n pageSize: PAGE_SIZE,\n }), [emVigor, search, 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 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 const filtros = (\n <FilterPanel\n title={t('inventory.filters.title')}\n dirty={filtrosPendentes}\n onApply={aplicarFiltros}\n applyLabel={t('inventory.filters.apply')}\n pendingTitle={t('inventory.filters.pending')}\n pendingHint={t('inventory.filters.pendingHint')}\n onClear={filtrosAtivos > 0 ? limparFiltros : undefined}\n clearLabel={t('inventory.filters.clear')}\n busy={productsLoading}\n >\n <FilterPanelField label={t('inventory.filters.kind')}>\n <RequiredFilter\n label={t('inventory.filters.kind')}\n value={productTypes.find((p) => p.value === typeFilter)?.label ?? t('inventory.filters.allKinds')}\n icon={Boxes}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!typeFilter} onClick={() => { setTypeFilter(undefined); close() }}>\n {t('inventory.filters.allKinds')}\n </FilterMenuRow>\n {productTypes.map((p) => (\n <FilterMenuRow key={p.value} active={typeFilter === p.value} onClick={() => { setTypeFilter(p.value); close() }}>\n <span className=\"truncate\">{p.label}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n\n {categories.length > 0 && (\n <FilterPanelField label={t('inventory.filters.category')}>\n <RequiredFilter\n label={t('inventory.filters.category')}\n value={categories.find((c) => c.id === categoryId)?.name ?? t('inventory.filters.allCategories')}\n icon={Layers}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!categoryId} onClick={() => { setCategoryId(''); close() }}>\n {t('inventory.filters.allCategories')}\n </FilterMenuRow>\n {categories.map((c) => (\n <FilterMenuRow key={c.id} active={categoryId === c.id} onClick={() => { setCategoryId(c.id); close() }}>\n <span className=\"truncate\">{c.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n\n <FilterPanelField label={t('inventory.filters.status')}>\n <RequiredFilter\n label={t('inventory.filters.status')}\n value={\n activeFilter === undefined\n ? t('inventory.filters.allStatuses')\n : activeFilter === 'true'\n ? t('inventory.productList.active')\n : t('inventory.productList.inactive')\n }\n icon={CircleCheck}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"space-y-0.5\">\n <FilterMenuRow active={activeFilter === undefined} onClick={() => { setActiveFilter(undefined); close() }}>\n {t('inventory.filters.allStatuses')}\n </FilterMenuRow>\n <FilterMenuRow active={activeFilter === 'true'} onClick={() => { setActiveFilter('true'); close() }}>\n {t('inventory.productList.active')}\n </FilterMenuRow>\n <FilterMenuRow active={activeFilter === 'false'} onClick={() => { setActiveFilter('false'); close() }}>\n {t('inventory.productList.inactive')}\n </FilterMenuRow>\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n </FilterPanel>\n )\n\n return (\n <div className=\"space-y-4\">\n {filtros}\n <CrudListView<Product>\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 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 </div>\n )\n}\n","import React from 'react'\nimport { SettingsGroup, ToggleRow, useOrganizationStore, useTenantPluginSettings } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { ResolvedInventoryConfig } from '../context'\n\n/**\n * Os módulos do Estoque que a CASA liga e desliga — não o pacote.\n *\n * `modules.recipes` na fábrica diz se este aplicativo OFERECE ficha técnica;\n * isto diz se esta conta a usa. Uma cozinha vive dela e um salão não tem\n * nenhuma — e os dois rodam o mesmo pacote central. Ver\n * FINANCIAL_MODULE_DEFAULTS, que é a mesma decisão no Financeiro.\n */\nexport const INVENTORY_MODULE_DEFAULTS = {\n recipes: true,\n requisitions: true,\n usageAudit: true,\n temperature: true,\n // Tabs another plugin lends to Inventory (invoice entry), switched off by id.\n hiddenViews: [] as string[],\n}\n\n/** Trades with nothing to produce. The sheet starts OFF there; the house can still turn it on. */\nconst NO_RECIPE_VERTICALS = new Set(['beauty'])\n\n/** The defaults for THIS account's trade — a salon does not open on a recipe book. */\nexport function inventoryModuleDefaults(verticalId?: string | null): typeof INVENTORY_MODULE_DEFAULTS {\n return NO_RECIPE_VERTICALS.has(verticalId ?? '')\n ? { ...INVENTORY_MODULE_DEFAULTS, recipes: false }\n : INVENTORY_MODULE_DEFAULTS\n}\n\n/** The house's module switches, over the defaults of its trade. One reader, so no screen disagrees. */\nexport function useInventoryHouseModules() {\n const verticalId = useOrganizationStore((state) => state.currentOrg?.verticalId)\n const defaults = React.useMemo(() => inventoryModuleDefaults(verticalId), [verticalId])\n return useTenantPluginSettings('inventory', defaults)\n}\n\n// Per-tenant defaults. Rows marked `pending` save but nothing reads them yet\n// (docs/status/SETTINGS-AUDIT.md).\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({ config }: { config?: ResolvedInventoryConfig }) {\n const t = useTranslation()\n const s = useTenantPluginSettings('inventory', INVENTORY_DEFAULTS)\n const mods = useInventoryHouseModules()\n return (\n <div className=\"space-y-4\">\n {/* Só o que o aplicativo OFERECE aparece aqui. */}\n <SettingsGroup title={t('inventory.settings.modules')} description={t('inventory.settings.modulesDesc')}>\n {config?.modules.recipes && (\n <ToggleRow\n label={t('inventory.settings.recipes')}\n description={t('inventory.settings.recipesDesc')}\n checked={mods.get('recipes')}\n onChange={(v) => mods.set('recipes', v)}\n />\n )}\n <ToggleRow label={t('inventory.settings.requisitions')} description={t('inventory.settings.requisitionsDesc')} checked={mods.get('requisitions')} onChange={(v) => mods.set('requisitions', v)} />\n <ToggleRow label={t('inventory.nav.usageAudit')} description={t('inventory.settings.usageAuditDesc')} checked={mods.get('usageAudit')} onChange={(v) => mods.set('usageAudit', v)} />\n <ToggleRow label={t('inventory.settings.temperature')} description={t('inventory.settings.temperatureDesc')} checked={mods.get('temperature')} onChange={(v) => mods.set('temperature', v)} />\n {(config?.extraViews ?? []).map((extra) => {\n const hidden = mods.get('hiddenViews')\n return (\n <ToggleRow\n key={extra.id}\n label={extra.label}\n checked={!hidden.includes(extra.id)}\n onChange={(v) => mods.set('hiddenViews', v ? hidden.filter((id) => id !== extra.id) : [...hidden, extra.id])}\n />\n )\n })}\n </SettingsGroup>\n <SettingsGroup title={t('inventory.settings.stockManagement')} description={t('inventory.settings.stockManagementDesc')}>\n <ToggleRow pending label={t('inventory.settings.lowStockAlerts')} description={t('inventory.settings.lowStockAlertsDesc')} checked={s.get('lowStockAlerts')} onChange={(v) => s.set('lowStockAlerts', v)} />\n <ToggleRow pending label={t('inventory.settings.requireReason')} description={t('inventory.settings.requireReasonDesc')} checked={s.get('requireReason')} onChange={(v) => s.set('requireReason', v)} />\n <ToggleRow pending 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 pending label={t('inventory.settings.requireSku')} description={t('inventory.settings.requireSkuDesc')} checked={s.get('requireSku')} onChange={(v) => s.set('requireSku', v)} />\n <ToggleRow pending 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 pending label={t('inventory.settings.lowStockEmail')} description={t('inventory.settings.lowStockEmailDesc')} checked={s.get('lowStockEmail')} onChange={(v) => s.set('lowStockEmail', v)} />\n <ToggleRow pending 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 { useOfferedPlugins } from '@fayz-ai/admin'\nimport { useInventoryHouseModules } from '../components/InventoryGeneralSettings'\n\n/**\n * Does this account sell from a menu? A shirt for sale is not a dish: prep\n * time, allergens and add-ons only belong where a trade offers the menu.\n * An app with no declared offer keeps the menu sheets, as before.\n */\nexport function useHasMenu(): boolean {\n const offered = useOfferedPlugins()\n return offered.length === 0 || offered.includes('menu')\n}\n\n/** Does this house use technical sheets? Its own switch, over its trade's default. */\nexport function useHasRecipes(): boolean {\n return useInventoryHouseModules().get('recipes')\n}\n","// Unit families and the portion × batch rule of a technical sheet.\n// Mirrors V1 (src/lib/unitConversion.ts + src/lib/recipeYield.ts): the stored\n// quantity is ALWAYS in the ingredient's base unit; a family unit is only how\n// the line is read and typed (0,07 L ⇄ 70 mL).\n\nexport interface UnitLike {\n id: string\n name: string\n abbreviation: string\n}\n\nexport type YieldMode = 'portion' | 'batch'\n\ntype Family = 'mass' | 'volume'\n\n// 'lt' is deliberately absent: in these catalogues LT is a can, not a litre.\nconst FAMILY_BY_ABBR: Record<string, { family: Family; toBase: number }> = {\n kg: { family: 'mass', toBase: 1000 },\n g: { family: 'mass', toBase: 1 },\n mg: { family: 'mass', toBase: 0.001 },\n l: { family: 'volume', toBase: 1000 },\n ml: { family: 'volume', toBase: 1 },\n}\n\nconst norm = (a?: string | null) => (a ?? '').trim().toLowerCase()\n\n/** Stabilises conversion floats (0.07 × 1000 = 70.00000000000001). */\nexport const roundSmart = (v: number): number => parseFloat(v.toFixed(9))\n\nexport function unitFamily(abbr?: string | null) {\n return FAMILY_BY_ABBR[norm(abbr)] ?? null\n}\n\nexport function sameFamilyUnits<U extends UnitLike>(all: U[], baseAbbr?: string | null): U[] {\n const fam = unitFamily(baseAbbr)\n if (!fam) return []\n return all.filter((u) => unitFamily(u.abbreviation)?.family === fam.family)\n}\n\nexport function convertUnit(value: number, fromAbbr?: string | null, toAbbr?: string | null): number | null {\n const f = unitFamily(fromAbbr)\n const t = unitFamily(toAbbr)\n if (!f || !t || f.family !== t.family) return null\n return roundSmart((value * f.toBase) / t.toBase)\n}\n\n/**\n * Reading unit for a base value: the largest family unit where the number is\n * ≥ 1 (0,08 kg → g). Null when the base already reads well.\n */\nexport function bestDisplayUnit<U extends UnitLike>(valueInBase: number, baseAbbr: string | null | undefined, candidates: U[]): U | null {\n const fam = unitFamily(baseAbbr)\n if (!fam || !valueInBase || Math.abs(valueInBase) >= 1) return null\n const opts = candidates\n .map((u) => ({ u, info: unitFamily(u.abbreviation) }))\n .filter((x): x is { u: U; info: { family: Family; toBase: number } } => !!x.info && x.info.family === fam.family)\n .sort((a, b) => b.info.toBase - a.info.toBase)\n for (const o of opts) {\n if (Math.abs((valueInBase * fam.toBase) / o.info.toBase) >= 1) return o.u\n }\n return opts.length ? opts[opts.length - 1].u : null\n}\n\n/** Yield in the product's base unit (2.400 g of a product counted in kg = 2,4). */\nexport function yieldInBase(yieldQty: number, yieldAbbr?: string | null, productAbbr?: string | null): number {\n const q = Number(yieldQty) || 0\n if (q <= 0) return 1\n if (!yieldAbbr || !productAbbr || norm(yieldAbbr) === norm(productAbbr)) return q\n return convertUnit(q, yieldAbbr, productAbbr) ?? q\n}\n\n/** Cost of ONE unit of the product: portion = the sum; batch = sum ÷ yield. */\nexport function costPerUnit(totalCost: number, mode: YieldMode | null | undefined, yieldBase: number): number {\n if (mode !== 'batch') return totalCost\n return yieldBase > 0 ? totalCost / yieldBase : totalCost\n}\n","import { formatCurrency } from '@fayz-ai/core'\nimport { useSaveBar } from '@fayz-ai/ui'\nexport const brl = (v: number) => formatCurrency(Number(v) || 0)\n\n/** The kit has no textarea; this matches its Input. */\nexport const TEXTAREA =\n 'w-full rounded-input border border-input bg-card px-3 py-2 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring resize-y'\n\n/**\n * Registers a tab's form with the page's save bar. Rendered only once the tab\n * has loaded: the product page registers its own (clean) entry, and the bar\n * shows the most recently mounted one — mounting after the page puts the\n * tab's on top.\n */\nexport function SaveBarSlot(props: Parameters<typeof useSaveBar>[0]) {\n useSaveBar(props)\n return null\n}\n","import React, { useState } from 'react'\nimport { Loader2 } from 'lucide-react'\nimport {\n AiActionButton, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { IngredientInfo } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { brl } from './shared'\n\n/** ✎ on a sheet line: the ingredient's cost, for every sheet that uses it. */\nexport function IngredientCostDialog({ ingredient, unitAbbr, onClose, onSaved }: {\n ingredient: IngredientInfo\n unitAbbr?: string\n onClose: () => void\n onSaved: (cost: number) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [price, setPrice] = useState(ingredient.cost > 0 ? String(ingredient.cost).replace('.', ',') : '')\n const [reasoning, setReasoning] = useState('')\n const [asking, setAsking] = useState(false)\n const [saving, setSaving] = useState(false)\n const value = parseFloat(price.replace(',', '.')) || 0\n\n const askAi = async () => {\n setAsking(true)\n try {\n const s = await provider.suggestIngredientCost!(ingredient.productId, ingredient.name)\n if (s.suggestedPrice > 0) {\n setPrice(String(s.suggestedPrice).replace('.', ','))\n setReasoning(s.reasoning ?? '')\n // The AI picks its own unit; say which, so a price per kg is not\n // typed into a line counted in grams without anyone noticing.\n if (s.unitAbbreviation && unitAbbr && s.unitAbbreviation.toLowerCase() !== unitAbbr.toLowerCase()) {\n toast.warning(t('inventory.sheet.aiUnitMismatch', { ai: s.unitAbbreviation, unit: unitAbbr }))\n }\n } else {\n toast.error(t('inventory.sheet.aiNoPrice'))\n }\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.aiFailed'))\n } finally {\n setAsking(false)\n }\n }\n\n const save = async () => {\n setSaving(true)\n try {\n await provider.setIngredientCost!(ingredient.productId, value)\n onSaved(value)\n toast.success(t('inventory.sheet.costUpdated', { name: ingredient.name, price: brl(value) }))\n onClose()\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.saveFailed'))\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent size=\"md\">\n <ModalHeader>\n <ModalTitle>{t('inventory.sheet.costDialogTitle')}: <span className=\"text-primary\">{ingredient.name}</span></ModalTitle>\n <ModalDescription>{t('inventory.sheet.costDialogHint')}</ModalDescription>\n </ModalHeader>\n <ModalBody>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">\n {t('inventory.sheet.costPrice')}{unitAbbr ? ` (${t('inventory.sheet.per')} ${unitAbbr})` : ''}\n </span>\n <div className=\"flex gap-2\">\n <Input inputMode=\"decimal\" value={price} onChange={(e) => setPrice(e.target.value)} placeholder=\"0,00\" autoFocus />\n {provider.suggestIngredientCost && (\n <AiActionButton type=\"button\" tone=\"soft\" onClick={() => void askAi()} busy={asking} className=\"shrink-0\">\n IA\n </AiActionButton>\n )}\n </div>\n </label>\n {reasoning && <p className=\"mt-2 text-xs text-muted-foreground\">{reasoning}</p>}\n <p className=\"mt-3 text-xs text-muted-foreground\">{t('inventory.sheet.costAppliesEverywhere')}</p>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={saving}>{t('common.cancel')}</Button>\n <Button onClick={() => void save()} disabled={saving || value <= 0}>\n {saving ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}{t('common.save')}\n </Button>\n </ModalFooter>\n {value <= 0 && price !== '' && <p className=\"px-6 pb-4 text-xs text-destructive\">{t('inventory.sheet.costInvalid')}</p>}\n </ModalContent>\n </Modal>\n )\n}\n","import React, { useRef, useState } from 'react'\nimport { Loader2, Sparkles, Upload, X } from 'lucide-react'\nimport {\n AiActionButton, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { Product } from '@fayz-ai/inventory/domain/product'\nimport type { ProductionStation, RecipeAiSuggestion } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { TEXTAREA } from './shared'\n\n/** \"Sugerir Ficha Técnica com IA\": fills the sheet on screen; saves nothing. */\nexport function RecipeAiDialog({ product, stations, onClose, onSuggestion }: {\n product: Product\n stations: ProductionStation[]\n onClose: () => void\n onSuggestion: (s: RecipeAiSuggestion) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [name, setName] = useState(product.name)\n const [description, setDescription] = useState(product.description ?? '')\n const [instructions, setInstructions] = useState('')\n const [images, setImages] = useState<string[]>(product.imageUrl ? [product.imageUrl] : [])\n const [uploading, setUploading] = useState(false)\n const [loading, setLoading] = useState(false)\n const fileRef = useRef<HTMLInputElement>(null)\n\n const upload = async (file?: File) => {\n if (!file || !provider.uploadAiReference) return\n setUploading(true)\n try {\n const url = await provider.uploadAiReference(file)\n setImages((xs) => [...xs, url])\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.uploadFailed'))\n } finally {\n setUploading(false)\n }\n }\n\n const generate = async () => {\n setLoading(true)\n try {\n const s = await provider.suggestRecipe!({\n productId: product.id, productName: name.trim(), description, imageUrls: images, instructions,\n })\n onSuggestion(s)\n toast.success(t('inventory.sheet.aiApplied'))\n onClose()\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.aiFailed'))\n } finally {\n setLoading(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o && !loading) onClose() }}>\n <ModalContent size=\"2xl\">\n <ModalHeader>\n <ModalTitle className=\"flex items-center gap-2\"><Sparkles className=\"h-5 w-5 text-primary\" /> {t('inventory.sheet.aiTitle')}</ModalTitle>\n </ModalHeader>\n <ModalBody className=\"space-y-4\">\n <div>\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.aiPhotos')}</span>\n <div className=\"flex flex-wrap gap-2\">\n {images.map((url, i) => (\n <div key={url} className=\"relative h-20 w-20 overflow-hidden rounded-lg border\">\n <img src={url} alt=\"\" className=\"h-full w-full object-cover\" />\n <Button variant=\"bare\" size=\"bare\" type=\"button\" aria-label={t('inventory.sheet.removePhoto')} onClick={() => setImages(images.filter((_, idx) => idx !== i))}\n className=\"font-normal absolute right-1 top-1 rounded-full bg-background/80 p-0.5\">\n <X className=\"h-3 w-3\" />\n </Button>\n </div>\n ))}\n {provider.uploadAiReference && (\n <Button variant=\"bare\" size=\"bare\" type=\"button\" onClick={() => fileRef.current?.click()} disabled={uploading} aria-label={t('inventory.sheet.addPhoto')}\n className=\"font-normal flex h-20 w-20 items-center justify-center rounded-lg border-2 border-dashed transition-colors hover:border-primary/50\">\n {uploading ? <Loader2 className=\"h-5 w-5 animate-spin\" /> : <Upload className=\"h-5 w-5 text-muted-foreground\" />}\n </Button>\n )}\n <input ref={fileRef} type=\"file\" accept=\"image/*\" className=\"hidden\" onChange={(e) => { void upload(e.target.files?.[0]); e.target.value = '' }} />\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">{t('inventory.sheet.aiPhotosHint')}</p>\n </div>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.aiProductName')}</span>\n <Input value={name} onChange={(e) => setName(e.target.value)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.description')}</span>\n <textarea className={TEXTAREA} rows={2} value={description} onChange={(e) => setDescription(e.target.value)} />\n </label>\n <div className=\"rounded-lg border bg-muted/40 p-3\">\n <div className=\"mb-1 text-xs font-medium\">{t('inventory.sheet.aiStations')}</div>\n <div className=\"flex flex-wrap gap-1.5\">\n {stations.length === 0 && <span className=\"text-xs text-muted-foreground\">{t('inventory.sheet.aiNoStations')}</span>}\n {stations.map((s) => <span key={s.id} className=\"rounded-full border bg-background px-2 py-0.5 text-xs\">{s.name}</span>)}\n </div>\n </div>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.aiInstructions')}</span>\n <textarea className={TEXTAREA} rows={3} value={instructions} onChange={(e) => setInstructions(e.target.value)} placeholder={t('inventory.sheet.aiInstructionsPlaceholder')} />\n </label>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.sheet.aiReplaces')}</p>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={loading}>{t('common.cancel')}</Button>\n <AiActionButton onClick={() => void generate()} busy={loading} busyLabel={t('inventory.sheet.aiGenerating')} disabled={!name.trim()}>\n {t('inventory.sheet.aiGenerate')}\n </AiActionButton>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n","import React, { useState } from 'react'\nimport { Loader2 } from 'lucide-react'\nimport {\n Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { MeasurementUnit } from '@fayz-ai/inventory/domain/product'\nimport type { RecipeSheetGroup } from '@fayz-ai/inventory/domain/recipe-sheet'\n\n/**\n * ⋮ → \"Transformar em produto intermediário\": a new Intermediário product with\n * this block as its own sheet. Written on confirm, as in V1 (V1-084) — the\n * difference is that its sheet goes through the same atomic save.\n */\nexport function TransformIntermediateDialog({ defaultName, units, group, onClose, onCreated }: {\n defaultName: string\n units: MeasurementUnit[]\n group: Omit<RecipeSheetGroup, 'name'>\n onClose: () => void\n onCreated: (productId: string) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const kg = units.find((u) => u.abbreviation.toLowerCase() === 'kg') ?? units.find((u) => u.abbreviation.toLowerCase() === 'g')\n const [name, setName] = useState(defaultName.trim())\n const [yieldQty, setYieldQty] = useState('1')\n const [unitId, setUnitId] = useState(kg?.id ?? '')\n const [saving, setSaving] = useState(false)\n const qty = parseFloat(yieldQty.replace(',', '.')) || 0\n const missing = !name.trim() ? t('inventory.sheet.transformNameRequired')\n : qty <= 0 ? t('inventory.sheet.transformYieldRequired')\n : !unitId ? t('inventory.sheet.transformUnitRequired') : null\n\n const create = async () => {\n if (missing) return\n setSaving(true)\n try {\n const dup = await provider.getProducts({ search: name.trim(), pageSize: 5 })\n if (dup.data.some((p) => p.name.trim().toLowerCase() === name.trim().toLowerCase())) {\n toast.error(t('inventory.sheet.transformDuplicate'))\n return\n }\n const product = await provider.createProduct({\n name: name.trim(),\n productType: 'intermediate',\n measurementUnitId: unitId,\n classification: { isIntermediate: true, isIngredient: false, isForSale: false, isAsset: false, isProduced: true },\n })\n await provider.saveRecipeSheet!({\n productId: product.id,\n name: name.trim(),\n yieldQuantity: qty,\n yieldUnitId: unitId,\n yieldMode: 'batch',\n instructions: group.preparationNotes,\n groups: [{ ...group, name: name.trim() }],\n outputs: [],\n }, null)\n toast.success(t('inventory.sheet.transformDone', { name: name.trim() }))\n onCreated(product.id)\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.transformFailed'))\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o && !saving) onClose() }}>\n <ModalContent size=\"md\">\n <ModalHeader>\n <ModalTitle>{t('inventory.sheet.transform')}</ModalTitle>\n <ModalDescription>{t('inventory.sheet.transformHint')}</ModalDescription>\n </ModalHeader>\n <ModalBody className=\"space-y-4\">\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.transformName')} *</span>\n <Input value={name} onChange={(e) => setName(e.target.value)} placeholder={t('inventory.sheet.transformNamePlaceholder')} autoFocus />\n </label>\n <div className=\"grid grid-cols-12 gap-3\">\n <label className=\"col-span-5 block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.yield')} *</span>\n <Input type=\"number\" step=\"0.001\" value={yieldQty} onChange={(e) => setYieldQty(e.target.value)} placeholder=\"500\" />\n </label>\n <label className=\"col-span-7 block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.unit')} *</span>\n <Select value={unitId || undefined} onValueChange={setUnitId}>\n <SelectTrigger><SelectValue placeholder={t('inventory.sheet.transformUnitPlaceholder')} /></SelectTrigger>\n <SelectContent>\n {units.map((u) => <SelectItem key={u.id} value={u.id}>{u.name} ({u.abbreviation})</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n </div>\n {missing && <p className=\"text-xs text-muted-foreground\">{missing}</p>}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={saving}>{t('common.cancel')}</Button>\n <Button onClick={() => void create()} disabled={saving || !!missing}>\n {saving && <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />}\n {saving ? t('inventory.sheet.transformCreating') : t('inventory.sheet.transformCreate')}\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n","import React, { useState } from 'react'\nimport { Loader2 } from 'lucide-react'\nimport {\n Button, CurrencyInput, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { IngredientInfo } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport type { MeasurementUnit } from '@fayz-ai/inventory/domain/product'\n\n/**\n * \"Criar insumo\" from a sheet line. The unit is asked for because the line's\n * quantity is stored in it — an ingredient without one can't be costed or\n * converted (g ↔ kg), which is the hole the migrated catalogue already has.\n */\nexport function QuickIngredientDialog({ defaultName, units, onClose, onCreated }: {\n defaultName: string\n units: MeasurementUnit[]\n onClose: () => void\n onCreated: (row: IngredientInfo) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [name, setName] = useState(defaultName)\n const [unitId, setUnitId] = useState('')\n const [cost, setCost] = useState(0)\n const [saving, setSaving] = useState(false)\n const missing = !name.trim() ? t('inventory.sheet.quickNameRequired') : !unitId ? t('inventory.sheet.quickUnitRequired') : null\n\n const create = async () => {\n if (missing) return\n setSaving(true)\n try {\n const p = await provider.createProduct({\n name: name.trim(),\n productType: 'ingredient',\n classification: { isIngredient: true },\n measurementUnitId: unitId,\n costPrice: cost > 0 ? cost : undefined,\n })\n toast.success(t('inventory.sheet.ingredientCreated', { name: name.trim() }))\n onCreated({ productId: p.id, name: p.name, cost: Number(p.costPrice) || cost, baseUnitId: p.measurementUnitId ?? unitId })\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.ingredientCreateFailed'))\n } finally {\n setSaving(false)\n }\n }\n\n const unit = units.find((u) => u.id === unitId)\n return (\n <Modal open onOpenChange={(o) => { if (!o && !saving) onClose() }}>\n <ModalContent size=\"md\">\n <ModalHeader>\n <ModalTitle>{t('inventory.sheet.quickTitle')}</ModalTitle>\n <ModalDescription>{t('inventory.sheet.quickHint')}</ModalDescription>\n </ModalHeader>\n <ModalBody className=\"space-y-4\">\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.quickName')} *</span>\n <Input value={name} onChange={(e) => setName(e.target.value)} autoFocus />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.quickUnit')} *</span>\n <Select value={unitId || undefined} onValueChange={setUnitId}>\n <SelectTrigger><SelectValue placeholder={t('inventory.sheet.transformUnitPlaceholder')} /></SelectTrigger>\n <SelectContent>\n {units.map((u) => <SelectItem key={u.id} value={u.id}>{u.name} ({u.abbreviation})</SelectItem>)}\n </SelectContent>\n </Select>\n <span className=\"mt-1 block text-xs text-muted-foreground\">{t('inventory.sheet.quickUnitHint')}</span>\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">\n {t('inventory.sheet.costPrice')}{unit ? ` (${t('inventory.sheet.per')} ${unit.abbreviation})` : ''}\n </span>\n <CurrencyInput value={cost} onChange={setCost} />\n </label>\n {missing && <p className=\"text-xs text-muted-foreground\">{missing}</p>}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={saving}>{t('common.cancel')}</Button>\n <Button onClick={() => void create()} disabled={saving || !!missing}>\n {saving && <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />}{t('inventory.sheet.quickCreate')}\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n","import type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { RecipeListRow } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { convertUnit, bestDisplayUnit } from '../../lib/recipe-units'\nimport { openPrintWindow, printDocument } from '@fayz-ai/ui'\nimport { brl } from './shared'\n\nconst esc = (s: unknown) =>\n String(s ?? '').replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[c]!))\n\n/**\n * The printable sheet, as V1 prints it, plus what V1 left out: components by\n * station and the preparation text. Opens in a new window and calls print.\n */\nexport async function printRecipe(provider: InventoryDataProvider, row: RecipeListRow): Promise<void> {\n // Open first, synchronously with the click: a window opened after an await\n // is a pop-up and gets blocked.\n const w = openPrintWindow()\n if (!w) throw new Error('Permita pop-ups para imprimir.')\n\n const [sheet, units, stations] = await Promise.all([\n provider.getRecipeSheet!(row.productId),\n provider.getMeasurementUnitList?.() ?? [],\n provider.getProductionStations?.() ?? [],\n ])\n const ids = sheet?.groups.flatMap((g) => g.ingredients.map((l) => l.productId)) ?? []\n const info = new Map((await (provider.getIngredientInfo?.(ids) ?? Promise.resolve([]))).map((i) => [i.productId, i]))\n const unit = new Map(units.map((u) => [u.id, u]))\n const station = new Map(stations.map((s) => [s.id, s.name]))\n const cmv = row.salePrice > 0 && row.cost > 0 ? (row.cost / row.salePrice) * 100 : null\n\n const groupsHtml = (sheet?.groups ?? []).map((g) => {\n const lines = g.ingredients.map((l) => {\n const i = info.get(l.productId)\n const baseAbbr = unit.get(i?.baseUnitId ?? l.unitId ?? '')?.abbreviation\n const display = l.displayUnitId ? unit.get(l.displayUnitId) : bestDisplayUnit(l.quantity, baseAbbr, units)\n const shown = display ? convertUnit(l.quantity, baseAbbr, display.abbreviation) : null\n const cost = (i?.cost ?? 0) * l.quantity\n return `<tr>\n <td>${esc(i?.name ?? '-')}</td>\n <td class=\"num\">${(shown ?? l.quantity).toLocaleString('pt-BR')} ${esc(shown != null ? display!.abbreviation : baseAbbr ?? '')}</td>\n <td class=\"num\">${i?.cost ? brl(i.cost) : '—'}</td>\n <td class=\"num\">${i?.cost ? brl(cost) : '—'}</td>\n <td>${esc(l.notes ?? '')}</td>\n </tr>`\n }).join('')\n return `<h2>${esc(g.name)}${g.stationId && station.get(g.stationId) ? ` <span class=\"muted\">· ${esc(station.get(g.stationId))}</span>` : ''}${g.estimatedMinutes ? ` <span class=\"muted\">· ${g.estimatedMinutes} min</span>` : ''}</h2>\n <table>\n <thead><tr><th>Insumo</th><th class=\"num\">Qtd</th><th class=\"num\">Custo Unit.</th><th class=\"num\">Subtotal</th><th>Obs.</th></tr></thead>\n <tbody>${lines || '<tr><td colspan=\"5\" class=\"empty\">Sem insumos</td></tr>'}</tbody>\n </table>\n ${g.preparationNotes ? `<div class=\"desc\"><b>Modo de preparo:</b> ${esc(g.preparationNotes)}</div>` : ''}`\n }).join('')\n\n printDocument({\n target: w,\n title: `Ficha Técnica - ${row.productName}`,\n css: `\n *{box-sizing:border-box} body{font-family:Arial,Helvetica,sans-serif;color:#111}\n h1{font-size:20px;margin:0 0 4px} h2{font-size:14px;margin:20px 0 4px} .muted{color:#666;font-size:12px;font-weight:normal}\n .meta{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:16px 0;padding:12px;border:1px solid #ddd;border-radius:6px}\n .meta div{font-size:12px} .meta b{display:block;font-size:11px;color:#666;margin-bottom:2px;text-transform:uppercase;letter-spacing:.4px}\n table{width:100%;border-collapse:collapse;margin-top:4px;font-size:13px}\n th,td{border-bottom:1px solid #eee;padding:6px 8px;text-align:left}\n th{background:#f6f6f6;font-size:11px;text-transform:uppercase;letter-spacing:.3px}\n td.num,th.num{text-align:right;font-variant-numeric:tabular-nums} td.empty{text-align:center;color:#888;padding:16px}\n .desc{margin-top:8px;font-size:13px;white-space:pre-wrap}\n \n`,\n body: `\n <h1>Ficha Técnica</h1>\n <div class=\"muted\">${esc(row.productName)}</div>\n ${row.description ? `<div class=\"desc\">${esc(row.description)}</div>` : ''}\n <div class=\"meta\">\n <div><b>Rendimento</b>${row.yieldQuantity ?? '-'} ${esc(row.yieldUnitAbbr ?? '')}</div>\n <div><b>Preparo</b>${row.preparationTimeMinutes ? row.preparationTimeMinutes + ' min' : '-'}</div>\n <div><b>Insumos</b>${row.ingredientCount}</div>\n <div><b>Custo</b>${brl(row.cost)}</div>\n <div><b>Venda</b>${brl(row.salePrice)}</div>\n <div><b>CMV</b>${cmv !== null ? cmv.toFixed(1).replace('.', ',') + '%' : '—'}</div>\n </div>\n ${groupsHtml}\n ${sheet?.instructions ? `<h2>Modo de Preparo Geral / Montagem</h2><div class=\"desc\">${esc(sheet.instructions)}</div>` : ''}\n`,\n })\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Plus, Trash2, MoreVertical, Package, Pencil, Printer } from 'lucide-react'\nimport {\n AiActionButton, Button, Card, CardContent, Input, SearchSelect, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,\n Dropdown, DropdownTrigger, DropdownContent, DropdownItem, DropdownSeparator,\n Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, Skeleton, toast,\n} from '@fayz-ai/ui'\nimport { errorMessage, useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { Product, MeasurementUnit } from '@fayz-ai/inventory/domain/product'\nimport type { IngredientInfo, ProductionStation, RecipeOutputType, RecipeSheet } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport {\n bestDisplayUnit, convertUnit, costPerUnit, roundSmart, sameFamilyUnits, yieldInBase, type YieldMode,\n} from '../../lib/recipe-units'\nimport { CMV_TONE, cmvBand, cmvPercent } from '@fayz-ai/inventory/domain/recipe'\nimport { IngredientCostDialog } from './IngredientCostDialog'\nimport { RecipeAiDialog } from './RecipeAiDialog'\nimport { TransformIntermediateDialog } from './TransformIntermediateDialog'\nimport { QuickIngredientDialog } from './QuickIngredientDialog'\nimport { brl, SaveBarSlot, TEXTAREA } from './shared'\nimport { printRecipe } from './printRecipe'\n\ninterface Line {\n key: string\n productId: string\n productName: string\n /** In the reading unit (displayUnitId, or the base when empty). */\n quantity: string\n displayUnitId: string\n notes: string\n /** Name the AI proposed when it found no catalogue match. */\n hint?: string\n}\n\ninterface Group {\n key: string\n name: string\n stationId: string\n preparationNotes: string\n estimatedMinutes: string\n lines: Line[]\n}\n\ninterface Output {\n key: string\n productId: string\n productName: string\n outputType: RecipeOutputType\n expectedQuantity: string\n measurementUnitId: string\n costShare: string\n}\n\nlet seq = 0\nconst key = () => `k${++seq}`\nconst num = (s: string) => parseFloat(String(s).replace(',', '.')) || 0\n\nconst OUTPUT_TYPES: RecipeOutputType[] = ['main', 'coproduct', 'byproduct', 'waste']\n\nexport function RecipeEditor({ product, onSaved }: {\n product: Product\n /** After a save: the product's cost and flags changed. */\n onSaved?: () => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n const [loading, setLoading] = useState(true)\n const [units, setUnits] = useState<MeasurementUnit[]>([])\n const [stations, setStations] = useState<ProductionStation[]>([])\n const [info, setInfo] = useState<Record<string, IngredientInfo>>({})\n const [productUnitId, setProductUnitId] = useState<string | undefined>(product.measurementUnitId)\n\n const [recipeId, setRecipeId] = useState<string | undefined>()\n const [name, setName] = useState('')\n const [description, setDescription] = useState('')\n const [yieldQuantity, setYieldQuantity] = useState('1')\n const [yieldUnitId, setYieldUnitId] = useState('')\n const [yieldMode, setYieldMode] = useState<YieldMode>('portion')\n const [prepTime, setPrepTime] = useState('')\n const [instructions, setInstructions] = useState('')\n const [groups, setGroups] = useState<Group[]>([])\n const [outputs, setOutputs] = useState<Output[]>([])\n const [dirty, setDirty] = useState(false)\n const [saving, setSaving] = useState(false)\n const [reloadKey, setReloadKey] = useState(0)\n\n const [aiOpen, setAiOpen] = useState(false)\n const [costFor, setCostFor] = useState<IngredientInfo | null>(null)\n const [transformGroup, setTransformGroup] = useState<string | null>(null)\n /** The line a «Criar insumo» fills once the product exists. */\n const [creating, setCreating] = useState<{ groupKey: string; lineKey: string; name: string } | null>(null)\n\n const unitById = useMemo(() => new Map(units.map((u) => [u.id, u])), [units])\n const abbr = useCallback((id?: string) => (id ? unitById.get(id)?.abbreviation : undefined), [unitById])\n\n const remember = useCallback((rows: IngredientInfo[]) => {\n if (rows.length) setInfo((prev) => ({ ...prev, ...Object.fromEntries(rows.map((r) => [r.productId, r])) }))\n }, [])\n\n // --- load -----------------------------------------------------------------\n useEffect(() => {\n let active = true\n setLoading(true)\n void (async () => {\n const [unitRows, stationRows, sheet] = await Promise.all([\n provider.getMeasurementUnitList?.() ?? [],\n provider.getProductionStations?.() ?? [],\n provider.getRecipeSheet?.(product.id) ?? null,\n ])\n const ids = [\n product.id,\n ...(sheet?.groups.flatMap((g) => g.ingredients.map((l) => l.productId)) ?? []),\n ...(sheet?.outputs.map((o) => o.productId) ?? []),\n ]\n const infoRows = await (provider.getIngredientInfo?.(ids) ?? Promise.resolve([]))\n if (!active) return\n const infoMap = Object.fromEntries(infoRows.map((r) => [r.productId, r]))\n const uById = new Map(unitRows.map((u) => [u.id, u]))\n setUnits(unitRows)\n setStations(stationRows)\n setInfo(infoMap)\n setProductUnitId(product.measurementUnitId ?? infoMap[product.id]?.baseUnitId)\n\n if (sheet) {\n setRecipeId(sheet.id)\n setName(sheet.name)\n setDescription(sheet.description ?? '')\n setYieldQuantity(String(sheet.yieldQuantity ?? 1))\n setYieldUnitId(sheet.yieldUnitId ?? '')\n setYieldMode(sheet.yieldMode)\n setPrepTime(sheet.preparationTimeMinutes != null ? String(sheet.preparationTimeMinutes) : '')\n setInstructions(sheet.instructions ?? '')\n setGroups(sheet.groups.map((g) => ({\n key: key(),\n name: g.name,\n stationId: g.stationId ?? '',\n preparationNotes: g.preparationNotes ?? '',\n estimatedMinutes: g.estimatedMinutes != null ? String(g.estimatedMinutes) : '',\n lines: g.ingredients.map((l) => {\n // Stored in the base unit; shown in the saved reading unit, or the\n // one where the number reads ≥ 1 (0,08 kg → 80 g), as V1 does.\n const baseId = infoMap[l.productId]?.baseUnitId ?? l.unitId\n const baseAbbr = baseId ? uById.get(baseId)?.abbreviation : undefined\n let displayId = l.displayUnitId ?? ''\n if (!displayId && baseAbbr) {\n const best = bestDisplayUnit(l.quantity, baseAbbr, unitRows)\n if (best && best.abbreviation !== baseAbbr) displayId = best.id\n }\n const shown = displayId ? convertUnit(l.quantity, baseAbbr, uById.get(displayId)?.abbreviation) : null\n return {\n key: key(),\n productId: l.productId,\n productName: infoMap[l.productId]?.name ?? '',\n quantity: String(shown ?? l.quantity),\n displayUnitId: shown == null ? '' : displayId,\n notes: l.notes ?? '',\n }\n }),\n })))\n setOutputs(sheet.outputs.map((o) => ({\n key: key(),\n productId: o.productId,\n productName: infoMap[o.productId]?.name ?? '',\n outputType: o.outputType,\n expectedQuantity: String(o.expectedQuantity),\n measurementUnitId: o.measurementUnitId ?? '',\n costShare: o.costShare != null ? String(o.costShare) : '',\n })))\n } else {\n setRecipeId(undefined)\n setName(product.name)\n setDescription('')\n setYieldQuantity('1')\n setYieldUnitId('')\n // A new intermediate's sheet is a batch; everything else, a portion.\n setYieldMode(product.classification?.isIntermediate ? 'batch' : 'portion')\n setPrepTime('')\n setInstructions('')\n setGroups([])\n setOutputs([])\n }\n setDirty(false)\n setLoading(false)\n })().catch((e) => {\n if (!active) return\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.loadFailed'))\n setLoading(false)\n })\n return () => { active = false }\n }, [provider, product.id, reloadKey]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // --- edit helpers ----------------------------------------------------------\n const touch = () => setDirty(true)\n const patchGroup = (gk: string, patch: Partial<Group>) => {\n setGroups((gs) => gs.map((g) => (g.key === gk ? { ...g, ...patch } : g))); touch()\n }\n const patchLine = (gk: string, lk: string, patch: Partial<Line>) => {\n setGroups((gs) => gs.map((g) => (g.key !== gk ? g : { ...g, lines: g.lines.map((l) => (l.key === lk ? { ...l, ...patch } : l)) })))\n touch()\n }\n const patchOutput = (ok: string, patch: Partial<Output>) => {\n setOutputs((os) => os.map((o) => (o.key === ok ? { ...o, ...patch } : o))); touch()\n }\n\n const baseAbbrOf = (productId: string) => abbr(info[productId]?.baseUnitId)\n const lineAbbr = (l: Line) => (l.displayUnitId ? abbr(l.displayUnitId) : baseAbbrOf(l.productId))\n const lineQtyInBase = (l: Line): number => {\n const q = num(l.quantity)\n if (!q || !l.displayUnitId) return q\n return convertUnit(q, abbr(l.displayUnitId), baseAbbrOf(l.productId)) ?? q\n }\n const lineCost = (l: Line): number | null => {\n const i = info[l.productId]\n const q = lineQtyInBase(l)\n if (!l.productId || !i || !q || !i.cost) return null\n return roundSmart(q * i.cost)\n }\n\n const changeDisplayUnit = (gk: string, l: Line, toId: string) => {\n const baseId = info[l.productId]?.baseUnitId\n const converted = convertUnit(num(l.quantity), lineAbbr(l), abbr(toId))\n patchLine(gk, l.key, {\n quantity: converted != null && l.quantity !== '' ? String(converted) : l.quantity,\n displayUnitId: toId === baseId ? '' : toId,\n })\n }\n\n // --- numbers ---------------------------------------------------------------\n const totalCost = groups.reduce((s, g) => s + g.lines.reduce((ss, l) => ss + (lineCost(l) ?? 0), 0), 0)\n const productAbbr = abbr(productUnitId)\n const yieldBase = yieldInBase(num(yieldQuantity) || 1, abbr(yieldUnitId), productAbbr)\n const unitCost = costPerUnit(totalCost, yieldMode, yieldBase)\n const salePrice = Number(product.salePrice) || 0\n const cmv = cmvPercent(unitCost, salePrice)\n\n // --- search ----------------------------------------------------------------\n const searchIngredients = useCallback(async (q: string) => {\n const rows = await (provider.searchIngredients?.(q) ?? Promise.resolve([]))\n return rows.map((r) => ({ id: r.productId, label: r.name, subtitle: abbr(r.baseUnitId), data: r }))\n }, [provider, abbr])\n\n\n // --- AI --------------------------------------------------------------------\n const applySuggestion = async (s: Awaited<ReturnType<NonNullable<typeof provider.suggestRecipe>>>) => {\n if (s.yieldQuantity) setYieldQuantity(String(s.yieldQuantity))\n if (s.yieldUnitId) setYieldUnitId(s.yieldUnitId)\n if (s.preparationTimeMinutes) setPrepTime(String(s.preparationTimeMinutes))\n if (s.generalDescription && !description) setDescription(s.generalDescription)\n const ids = s.groups.flatMap((g) => g.ingredients.map((i) => i.productId).filter(Boolean) as string[])\n const rows = ids.length ? await (provider.getIngredientInfo?.(ids) ?? Promise.resolve([])) : []\n remember(rows)\n const byId = new Map(rows.map((r) => [r.productId, r]))\n // Same as V1: the suggestion replaces every component. Nothing is saved.\n setGroups(s.groups.map((g) => ({\n key: key(),\n name: g.name,\n stationId: g.stationId ?? '',\n preparationNotes: g.preparationNotes ?? '',\n estimatedMinutes: '',\n lines: g.ingredients.map((i) => {\n const baseAbbr = abbr((i.productId && byId.get(i.productId)?.baseUnitId) || i.unitId)\n const best = baseAbbr ? bestDisplayUnit(Number(i.quantity) || 0, baseAbbr, units) : null\n const shown = best ? convertUnit(Number(i.quantity) || 0, baseAbbr, best.abbreviation) : null\n return {\n key: key(),\n productId: i.productId ?? '',\n productName: (i.productId && byId.get(i.productId)?.name) || '',\n quantity: String(shown ?? i.quantity ?? ''),\n displayUnitId: shown != null && best ? best.id : '',\n notes: i.notes ?? '',\n hint: i.productId ? undefined : i.productNameHint,\n }\n }),\n })))\n touch()\n }\n\n // --- save ------------------------------------------------------------------\n const save = async () => {\n if (!name.trim()) { toast.error(t('inventory.sheet.nameRequired')); return }\n const usable = outputs.filter((o) => o.productId && num(o.expectedQuantity) > 0 && o.outputType !== 'waste')\n const withShare = usable.filter((o) => o.costShare.trim() !== '')\n if (withShare.length > 0) {\n const sum = withShare.reduce((a, o) => a + num(o.costShare), 0)\n if (withShare.length !== usable.length || Math.abs(sum - 100) > 0.01) {\n toast.error(t('inventory.sheet.outputShareTitle'), { description: t('inventory.sheet.outputShareHint') })\n return\n }\n }\n const sheet: RecipeSheet = {\n id: recipeId,\n productId: product.id,\n name: name.trim(),\n description: description.trim() || undefined,\n yieldQuantity: num(yieldQuantity) || 1,\n yieldUnitId: yieldUnitId || undefined,\n yieldMode,\n preparationTimeMinutes: prepTime ? parseInt(prepTime, 10) : undefined,\n instructions: instructions.trim() || undefined,\n groups: groups\n .filter((g) => g.name.trim() || g.lines.length > 0)\n .map((g) => ({\n name: g.name.trim(),\n stationId: g.stationId || undefined,\n preparationNotes: g.preparationNotes.trim() || undefined,\n estimatedMinutes: g.estimatedMinutes ? parseInt(g.estimatedMinutes, 10) : undefined,\n ingredients: g.lines.filter((l) => l.productId && num(l.quantity) > 0).map((l) => ({\n productId: l.productId,\n quantity: lineQtyInBase(l),\n unitId: info[l.productId]?.baseUnitId,\n displayUnitId: l.displayUnitId || undefined,\n notes: l.notes.trim() || undefined,\n })),\n })),\n outputs: outputs.filter((o) => o.productId && num(o.expectedQuantity) > 0).map((o) => ({\n productId: o.productId,\n outputType: o.outputType,\n expectedQuantity: num(o.expectedQuantity),\n measurementUnitId: o.measurementUnitId || undefined,\n costShare: o.outputType === 'waste' || o.costShare.trim() === '' ? null : num(o.costShare),\n })),\n }\n setSaving(true)\n try {\n const id = await provider.saveRecipeSheet!(sheet, unitCost > 0 ? roundSmart(unitCost) : null)\n setRecipeId(id)\n setDirty(false)\n toast.success(t('inventory.sheet.saved'))\n onSaved?.()\n setReloadKey((k) => k + 1)\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.sheet.saveFailed'))\n } finally {\n setSaving(false)\n }\n }\n\n\n if (loading) return <EditorSkeleton />\n\n const stationOptions = stations.map((s) => ({ value: s.id, label: s.name }))\n const unitOptions = units.map((u) => ({ value: u.id, label: `${u.name} (${u.abbreviation})` }))\n\n return (\n <TooltipProvider delayDuration={300}>\n <SaveBarSlot dirty={dirty} saving={saving} onSave={() => { void save() }} onDiscard={() => setReloadKey((k) => k + 1)} saveLabel={t('inventory.sheet.save')} />\n <style>{SHEET_LAYOUT}</style>\n <div className=\"fz-container space-y-6\">\n {/* Header */}\n <div className=\"rs-head\">\n <Field className=\"rs-name\" label={`${t('inventory.sheet.name')} *`}>\n <Input value={name} onChange={(e) => { setName(e.target.value); touch() }} placeholder={t('inventory.sheet.namePlaceholder')} />\n </Field>\n <Field label={t('inventory.sheet.yield')}>\n <Input type=\"number\" step=\"0.01\" value={yieldQuantity} onChange={(e) => { setYieldQuantity(e.target.value); touch() }} placeholder=\"1\" />\n </Field>\n <Field label={t('inventory.sheet.yieldUnit')}>\n <PlainSelect value={yieldUnitId} onChange={(v) => { setYieldUnitId(v); touch() }} options={unitOptions} placeholder={t('inventory.sheet.none')} clearable />\n </Field>\n <Field label={t('inventory.sheet.yieldMode')}>\n <Select value={yieldMode} onValueChange={(v) => { setYieldMode(v as YieldMode); touch() }}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"portion\">{t('inventory.sheet.yieldMode.portion')}</SelectItem>\n <SelectItem value=\"batch\">{t('inventory.sheet.yieldMode.batch')}</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <Field label={t('inventory.sheet.prepTime')}>\n <Input type=\"number\" value={prepTime} onChange={(e) => { setPrepTime(e.target.value); touch() }} placeholder=\"30\" />\n </Field>\n <p className=\"rs-full -mt-2 text-xs text-muted-foreground\">{t(`inventory.sheet.yieldMode.${yieldMode}Hint`)}</p>\n <Field className=\"rs-full\" label={t('inventory.sheet.description')}>\n <textarea className={TEXTAREA} rows={2} value={description} onChange={(e) => { setDescription(e.target.value); touch() }} placeholder={t('inventory.sheet.descriptionPlaceholder')} />\n </Field>\n </div>\n\n {/* Cost / price / CMV */}\n <Card>\n <CardContent className=\"grid grid-cols-3 gap-4 py-4\">\n <div>\n <p className=\"text-xs text-muted-foreground\">\n {t('inventory.sheet.costPrice')}{yieldMode === 'batch' && productAbbr ? ` (${t('inventory.sheet.per')} ${productAbbr})` : ''}\n </p>\n <p className=\"text-lg font-semibold tabular-nums\">{brl(unitCost)}</p>\n {yieldMode === 'batch' && <p className=\"text-xs text-muted-foreground\">{t('inventory.sheet.batchCost')}: {brl(totalCost)}</p>}\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.sheet.salePrice')}</p>\n <p className=\"text-lg font-semibold tabular-nums\">{brl(salePrice)}</p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground\">{t('inventory.sheet.cmv')}</p>\n {/* No cost means no CMV — \"0,0%\" would read as total margin (V1-083). */}\n <p className={`text-lg font-semibold tabular-nums ${cmv != null ? CMV_TONE[cmvBand(cmv)!] : ''}`}>\n {cmv != null && unitCost > 0 ? `${cmv.toLocaleString('pt-BR', { minimumFractionDigits: 1, maximumFractionDigits: 1 })} %` : '—'}\n </p>\n </div>\n </CardContent>\n </Card>\n\n {/* Components */}\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">{t('inventory.sheet.components')}</h3>\n <div className=\"flex items-center gap-2\">\n <Tooltip>\n <TooltipTrigger asChild>\n {/* span: a disabled button fires no hover, and the tooltip is what explains why. */}\n <span>\n <Button\n type=\"button\" variant=\"outline\" size=\"sm\"\n disabled={!recipeId || dirty}\n onClick={() => {\n printRecipe(provider, {\n productId: product.id,\n productName: product.name,\n recipeId,\n description: description || undefined,\n ingredientCount: groups.reduce((n, g) => n + g.lines.length, 0),\n yieldQuantity: num(yieldQuantity) || undefined,\n yieldUnitAbbr: abbr(yieldUnitId),\n preparationTimeMinutes: num(prepTime) || undefined,\n cost: unitCost,\n salePrice,\n isForSale: Boolean(product.classification?.isForSale),\n isIntermediate: Boolean(product.classification?.isIntermediate),\n }).catch((e) => toast.error(errorMessage(e)))\n }}\n >\n <Printer className=\"mr-1 h-3.5 w-3.5\" /> {t('inventory.sheet.print')}\n </Button>\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {!recipeId ? t('inventory.recipes.printNoSheet') : dirty ? t('inventory.sheet.printSaveFirst') : t('inventory.recipes.print')}\n </TooltipContent>\n </Tooltip>\n {provider.suggestRecipe && (\n <AiActionButton type=\"button\" tone=\"soft\" size=\"sm\" onClick={() => setAiOpen(true)}>\n {t('inventory.sheet.suggestAi')}\n </AiActionButton>\n )}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => { setGroups((gs) => [...gs, { key: key(), name: '', stationId: '', preparationNotes: '', estimatedMinutes: '', lines: [] }]); touch() }}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" /> {t('inventory.sheet.addGroup')}\n </Button>\n </div>\n </div>\n\n {groups.length === 0 ? (\n <Card>\n <CardContent className=\"py-8 text-center text-sm text-muted-foreground\">{t('inventory.sheet.noComponents')}</CardContent>\n </Card>\n ) : (\n <div className=\"space-y-4\">\n {groups.map((g) => (\n <Card key={g.key}>\n <div className=\"rs-comp border-b px-4 py-3\">\n <Field label={t('inventory.sheet.componentName')} small>\n <Input value={g.name} onChange={(e) => patchGroup(g.key, { name: e.target.value })} placeholder={t('inventory.sheet.componentNamePlaceholder')} />\n </Field>\n <Field label={t('inventory.sheet.station')} small>\n <PlainSelect value={g.stationId} onChange={(v) => patchGroup(g.key, { stationId: v })} options={stationOptions}\n placeholder={stations.length ? t('inventory.sheet.stationPlaceholder') : t('inventory.sheet.noStations')} clearable />\n </Field>\n <Field label={t('inventory.sheet.estimatedMinutes')} small>\n <Input inputMode=\"numeric\" value={g.estimatedMinutes} onChange={(e) => patchGroup(g.key, { estimatedMinutes: e.target.value.replace(/\\D/g, '') })} placeholder={t('inventory.sheet.estimatedMinutesPlaceholder')} />\n </Field>\n <div className=\"rs-comp-menu flex justify-end\">\n <Dropdown>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={t('inventory.sheet.componentMenu')}><MoreVertical className=\"h-4 w-4\" /></Button>\n </DropdownTrigger>\n </TooltipTrigger>\n <TooltipContent>{t('inventory.sheet.componentMenu')}</TooltipContent>\n </Tooltip>\n <DropdownContent align=\"end\" className=\"w-64\">\n <DropdownItem onSelect={() => {\n if (!g.lines.some((l) => l.productId && num(l.quantity) > 0)) { toast.error(t('inventory.sheet.transformNeedsLines')); return }\n setTransformGroup(g.key)\n }}>\n <Package className=\"mr-2 h-4 w-4\" /> {t('inventory.sheet.transform')}\n </DropdownItem>\n <DropdownSeparator />\n <DropdownItem className=\"text-destructive focus:text-destructive\" onSelect={() => { setGroups((gs) => gs.filter((x) => x.key !== g.key)); touch() }}>\n <Trash2 className=\"mr-2 h-4 w-4\" /> {t('inventory.sheet.deleteComponent')}\n </DropdownItem>\n </DropdownContent>\n </Dropdown>\n </div>\n </div>\n\n <CardContent className=\"space-y-3 px-4 pb-4 pt-3\">\n {g.lines.length === 0 ? (\n <p className=\"py-3 text-center text-xs text-muted-foreground\">{t('inventory.sheet.noLines')}</p>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"rs-line-head gap-3 px-1 text-xs font-medium text-muted-foreground\">\n <span>{t('inventory.sheet.ingredient')}</span>\n <span>{t('inventory.sheet.quantity')}</span>\n <span>{t('inventory.sheet.notes')}</span>\n <span className=\"text-right\">{t('inventory.sheet.cost')}</span>\n <span />\n </div>\n {g.lines.map((l) => {\n const i = info[l.productId]\n const baseId = i?.baseUnitId\n const baseAbbr = abbr(baseId)\n const family = baseAbbr ? sameFamilyUnits(units, baseAbbr) : []\n const c = lineCost(l)\n return (\n <div key={l.key} className=\"rs-line\">\n <div className=\"min-w-0\">\n <SearchSelect\n value={l.productId}\n displayValue={l.productName}\n onChange={(id, opt) => {\n if (opt?.data) remember([opt.data as IngredientInfo])\n patchLine(g.key, l.key, { productId: id, productName: opt?.label ?? '', displayUnitId: '', hint: undefined })\n }}\n onSearch={searchIngredients}\n placeholder={t('inventory.sheet.searchIngredient')}\n allowCreate\n createLabel={t('inventory.sheet.createIngredient')}\n onCreate={(q) => setCreating({ groupKey: g.key, lineKey: l.key, name: q })}\n />\n {!l.productId && l.hint && (\n <p className=\"mt-1 flex flex-wrap items-center gap-2 text-[11px] text-amber-600 dark:text-amber-400\">\n <span>{t('inventory.sheet.aiHint')}: <strong>{l.hint}</strong></span>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 px-2 text-[11px]\" onClick={() => setCreating({ groupKey: g.key, lineKey: l.key, name: l.hint! })}>\n <Plus className=\"mr-1 h-3 w-3\" /> {t('inventory.sheet.create')}\n </Button>\n </p>\n )}\n </div>\n <div className=\"flex\">\n <Input type=\"number\" step=\"0.001\" className=\"min-w-0 flex-1 rounded-r-none text-right tabular-nums\" value={l.quantity} placeholder=\"0\"\n aria-label={t('inventory.sheet.quantity')}\n onChange={(e) => patchLine(g.key, l.key, { quantity: e.target.value })} />\n {family.length > 1 && baseId ? (\n <Select value={l.displayUnitId || baseId} onValueChange={(v) => changeDisplayUnit(g.key, l, v)}>\n <SelectTrigger className=\"w-[76px] shrink-0 rounded-l-none border-l-0 bg-muted/50 px-2\" aria-label={t('inventory.sheet.unit')}>\n <span>{abbr(l.displayUnitId || baseId) ?? '—'}</span>\n </SelectTrigger>\n <SelectContent>\n {family.map((u) => <SelectItem key={u.id} value={u.id}>{u.abbreviation} ({u.name})</SelectItem>)}\n </SelectContent>\n </Select>\n ) : (\n <span className=\"flex shrink-0 items-center rounded-r-input border border-l-0 border-input bg-muted/50 px-2.5 text-sm text-muted-foreground\">{baseAbbr ?? '—'}</span>\n )}\n </div>\n <Input value={l.notes} onChange={(e) => patchLine(g.key, l.key, { notes: e.target.value })} placeholder={t('inventory.sheet.notes')} aria-label={t('inventory.sheet.notes')} />\n <div className=\"flex items-center justify-end gap-1 text-sm tabular-nums\">\n <span className={c == null ? 'text-muted-foreground' : ''}>{c != null ? brl(c) : '—'}</span>\n {l.productId && i && provider.setIngredientCost && (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" className=\"h-7 w-7\" aria-label={t('inventory.sheet.updateCost')} onClick={() => setCostFor(i)}>\n <Pencil className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n {i.cost > 0\n ? t('inventory.sheet.updateCostCurrent', { price: brl(i.cost), unit: baseAbbr ? `/${baseAbbr}` : '' })\n : t('inventory.sheet.setCost')}\n </TooltipContent>\n </Tooltip>\n )}\n </div>\n <div className=\"flex justify-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" aria-label={t('inventory.sheet.removeLine')}\n onClick={() => patchGroup(g.key, { lines: g.lines.filter((x) => x.key !== l.key) })}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('inventory.sheet.removeLine')}</TooltipContent>\n </Tooltip>\n </div>\n </div>\n )\n })}\n </div>\n )}\n <div className=\"flex justify-end\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => patchGroup(g.key, { lines: [...g.lines, { key: key(), productId: '', productName: '', quantity: '', displayUnitId: '', notes: '' }] })}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" /> {t('inventory.sheet.addLine')}\n </Button>\n </div>\n <Field label={t('inventory.sheet.componentPrep')} small>\n <textarea className={TEXTAREA} rows={2} value={g.preparationNotes} onChange={(e) => patchGroup(g.key, { preparationNotes: e.target.value })} placeholder={t('inventory.sheet.componentPrepPlaceholder')} />\n </Field>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {/* Outputs */}\n <Card>\n <div className=\"flex items-start justify-between gap-3 px-4 pb-2 pt-4\">\n <div>\n <p className=\"text-sm font-semibold\">{t('inventory.sheet.outputs')}</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">{t('inventory.sheet.outputsHint')}</p>\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"shrink-0\" onClick={() => {\n setOutputs((os) => [...os, { key: key(), productId: '', productName: '', outputType: os.length === 0 ? 'main' : 'coproduct', expectedQuantity: '', measurementUnitId: yieldUnitId, costShare: '' }])\n touch()\n }}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" /> {t('inventory.sheet.addOutput')}\n </Button>\n </div>\n {outputs.length > 0 && (\n <CardContent className=\"space-y-2 px-4 pb-4 pt-1\">\n <div className=\"rs-out-head gap-3 px-1 text-xs font-medium text-muted-foreground\">\n <span>{t('inventory.sheet.product')}</span>\n <span>{t('inventory.sheet.outputType')}</span>\n <span>{t('inventory.sheet.expectedQty')}</span>\n <span>{t('inventory.sheet.unit')}</span>\n <span>{t('inventory.sheet.costShare')}</span>\n <span />\n </div>\n {outputs.map((o) => (\n <div key={o.key} className=\"rs-out\">\n <SearchSelect value={o.productId} displayValue={o.productName}\n onChange={(id, opt) => patchOutput(o.key, { productId: id, productName: opt?.label ?? '' })}\n onSearch={searchIngredients} placeholder={t('inventory.sheet.searchIngredient')} />\n <Select value={o.outputType} onValueChange={(v) => patchOutput(o.key, { outputType: v as RecipeOutputType })}>\n <SelectTrigger aria-label={t('inventory.sheet.outputType')}><SelectValue /></SelectTrigger>\n <SelectContent>\n {OUTPUT_TYPES.map((ot) => <SelectItem key={ot} value={ot}>{t(`inventory.sheet.outputType.${ot}`)}</SelectItem>)}\n </SelectContent>\n </Select>\n <Input inputMode=\"decimal\" value={o.expectedQuantity} aria-label={t('inventory.sheet.expectedQty')} onChange={(e) => patchOutput(o.key, { expectedQuantity: e.target.value })} />\n <PlainSelect value={o.measurementUnitId} onChange={(v) => patchOutput(o.key, { measurementUnitId: v })} options={unitOptions} placeholder={t('inventory.sheet.unit')} />\n <Input inputMode=\"decimal\" aria-label={t('inventory.sheet.costShare')}\n placeholder={o.outputType === 'waste' ? '—' : t('inventory.sheet.auto')}\n disabled={o.outputType === 'waste'}\n value={o.outputType === 'waste' ? '' : o.costShare}\n onChange={(e) => patchOutput(o.key, { costShare: e.target.value })} />\n <div className=\"flex justify-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" aria-label={t('inventory.sheet.removeOutput')}\n onClick={() => { setOutputs((os) => os.filter((x) => x.key !== o.key)); touch() }}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('inventory.sheet.removeOutput')}</TooltipContent>\n </Tooltip>\n </div>\n </div>\n ))}\n </CardContent>\n )}\n </Card>\n\n <Field label={t('inventory.sheet.instructions')}>\n <textarea className={TEXTAREA} rows={4} value={instructions} onChange={(e) => { setInstructions(e.target.value); touch() }} placeholder={t('inventory.sheet.instructionsPlaceholder')} />\n </Field>\n\n </div>\n\n {aiOpen && (\n <RecipeAiDialog\n product={product}\n stations={stations}\n onClose={() => setAiOpen(false)}\n onSuggestion={(s) => { void applySuggestion(s) }}\n />\n )}\n {costFor && (\n <IngredientCostDialog\n ingredient={costFor}\n unitAbbr={abbr(costFor.baseUnitId)}\n onClose={() => setCostFor(null)}\n onSaved={(cost) => remember([{ ...costFor, cost }])}\n />\n )}\n {creating && (\n <QuickIngredientDialog\n defaultName={creating.name}\n units={units}\n onClose={() => setCreating(null)}\n onCreated={(row) => {\n remember([row])\n patchLine(creating.groupKey, creating.lineKey, { productId: row.productId, productName: row.name, hint: undefined, displayUnitId: '' })\n setCreating(null)\n }}\n />\n )}\n {transformGroup && (() => {\n const g = groups.find((x) => x.key === transformGroup)\n if (!g) return null\n return (\n <TransformIntermediateDialog\n defaultName={g.name}\n units={units}\n group={{\n stationId: g.stationId || undefined,\n preparationNotes: g.preparationNotes.trim() || undefined,\n ingredients: g.lines.filter((l) => l.productId && num(l.quantity) > 0).map((l) => ({\n productId: l.productId,\n quantity: lineQtyInBase(l),\n unitId: info[l.productId]?.baseUnitId,\n displayUnitId: l.displayUnitId || undefined,\n notes: l.notes.trim() || undefined,\n })),\n }}\n onClose={() => setTransformGroup(null)}\n onCreated={() => {\n // V1: the block leaves this sheet; the intermediate can now be added as an item.\n setGroups((gs) => gs.filter((x) => x.key !== transformGroup))\n setTransformGroup(null)\n touch()\n }}\n />\n )\n })()}\n </TooltipProvider>\n )\n}\n\n// Sized by the PANEL, not the window: the sheet lives in a product page next\n// to the module rail, and `md:` read the 1440px monitor while the panel had\n// 800px — five header fields squeezed to 120px each.\n// An ingredient row is one line from 44rem: it has two fixed fields and two\n// that flex, and stacking it into three lines at 900px tripled the page.\nconst SHEET_LAYOUT = `\n.rs-head{display:grid;gap:1rem;grid-template-columns:repeat(2,minmax(0,1fr))}\n.rs-head>.rs-name,.rs-head>.rs-full{grid-column:1/-1}\n.rs-comp{display:grid;gap:.75rem;grid-template-columns:minmax(0,1fr) auto;align-items:end}\n.rs-comp>*:not(.rs-comp-menu){grid-column:1}\n.rs-comp>.rs-comp-menu{grid-column:2;grid-row:1}\n.rs-line,.rs-out{display:grid;gap:.5rem;border:1px solid hsl(var(--border));border-radius:.5rem;padding:.5rem}\n.rs-line-head,.rs-out-head{display:none}\n.rs-line{grid-template-columns:minmax(0,1fr) auto;align-items:center}\n.rs-line>:nth-child(1),.rs-line>:nth-child(2),.rs-line>:nth-child(3){grid-column:1/-1}\n.rs-line>:nth-child(4){justify-content:flex-start}\n@container (min-width: 30rem){\n .rs-line{grid-template-columns:minmax(0,1fr) minmax(0,1.3fr) auto auto}\n .rs-line>:nth-child(2){grid-column:1}\n .rs-line>:nth-child(3){grid-column:2/-1}\n .rs-line>:nth-child(4){grid-column:1/3;justify-content:flex-end}\n}\n@container (min-width: 44rem){\n .rs-head{grid-template-columns:repeat(4,minmax(0,1fr))}\n .rs-comp{grid-template-columns:minmax(0,1fr) minmax(0,1fr) 9rem auto}\n .rs-comp>*:not(.rs-comp-menu){grid-column:auto}\n .rs-comp>.rs-comp-menu{grid-column:4}\n .rs-line,.rs-line-head{display:grid;grid-template-columns:minmax(0,2fr) 170px minmax(0,1.2fr) 96px 36px;align-items:center;gap:.5rem;border:0;padding:0}\n .rs-line>*{grid-column:auto !important}\n .rs-line>:nth-child(4){justify-content:flex-end}\n}\n@container (min-width: 60rem){\n .rs-head{grid-template-columns:minmax(0,2.2fr) repeat(4,minmax(0,1fr))}\n .rs-head>.rs-name{grid-column:auto}\n .rs-line,.rs-line-head{grid-template-columns:minmax(0,2fr) 200px minmax(0,1.4fr) 120px 36px;gap:.75rem}\n .rs-out,.rs-out-head{display:grid;grid-template-columns:minmax(0,2fr) 150px 110px 160px 100px 36px;align-items:center;gap:.75rem;border:0;padding:0}\n}\n`\n\nfunction Field({ label, children, className, small }: { label: string; children: React.ReactNode; className?: string; small?: boolean }) {\n return (\n <label className={`block ${className ?? ''}`}>\n <span className={`mb-1 block font-medium ${small ? 'text-xs' : 'text-sm'}`}>{label}</span>\n {children}\n </label>\n )\n}\n\n/** A Select with an optional \"Nenhuma\" entry — Radix forbids an empty value. */\nfunction PlainSelect({ value, onChange, options, placeholder, clearable }: {\n value: string\n onChange: (v: string) => void\n options: Array<{ value: string; label: string }>\n placeholder: string\n clearable?: boolean\n}) {\n const NONE = '__none__'\n return (\n <Select value={value || (clearable ? NONE : undefined)} onValueChange={(v) => onChange(v === NONE ? '' : v)}>\n <SelectTrigger aria-label={placeholder}><SelectValue placeholder={placeholder} /></SelectTrigger>\n <SelectContent>\n {clearable && <SelectItem value={NONE}><span className=\"text-muted-foreground\">{placeholder}</span></SelectItem>}\n {options.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}\n </SelectContent>\n </Select>\n )\n}\n\n/** The sheet's own shape: header fields, the three numbers, one component. */\nfunction EditorSkeleton() {\n const bar = 'bg-foreground/[0.08]'\n return (\n <div className=\"space-y-6\" aria-busy=\"true\">\n <div className=\"grid grid-cols-12 gap-4\">\n {['md:col-span-4', 'md:col-span-2', 'md:col-span-2', 'md:col-span-2', 'md:col-span-2'].map((span, i) => (\n <div key={i} className={`col-span-12 space-y-2 ${span}`}>\n <Skeleton className={`h-3.5 w-24 ${bar}`} />\n <Skeleton className={`h-10 w-full rounded-input ${bar}`} />\n </div>\n ))}\n <div className=\"col-span-12 space-y-2\">\n <Skeleton className={`h-3.5 w-28 ${bar}`} />\n <Skeleton className={`h-14 w-full rounded-input ${bar}`} />\n </div>\n </div>\n <div className=\"grid grid-cols-3 gap-4 rounded-card border bg-card p-4\">\n {[0, 1, 2].map((i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className={`h-3 w-20 ${bar}`} />\n <Skeleton className={`h-6 w-24 ${bar}`} />\n </div>\n ))}\n </div>\n <div className=\"flex items-center justify-between\">\n <Skeleton className={`h-4 w-64 ${bar}`} />\n <Skeleton className={`h-8 w-56 ${bar}`} />\n </div>\n <div className=\"rounded-card border bg-card\">\n <div className=\"grid grid-cols-3 gap-3 border-b p-4\">\n {[0, 1, 2].map((i) => <Skeleton key={i} className={`h-10 w-full rounded-input ${bar}`} />)}\n </div>\n <div className=\"space-y-3 p-4\">\n {[0, 1, 2, 3, 4].map((i) => (\n <div key={i} className=\"grid grid-cols-[2fr_1fr_1.4fr_80px] gap-3\">\n <Skeleton className={`h-9 rounded-input ${bar}`} />\n <Skeleton className={`h-9 rounded-input ${bar}`} />\n <Skeleton className={`h-9 rounded-input ${bar}`} />\n <Skeleton className={`h-4 self-center ${bar}`} />\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","import React from 'react'\nimport type { Product } from '@fayz-ai/inventory/domain/product'\nimport { RecipeEditor } from './recipe/RecipeEditor'\n\n/**\n * Ficha Técnica tab of the product — the same sheet the Fichas Técnicas list\n * opens. `onChanged` reloads the product: saving rewrites its cost and marks\n * it as produced.\n */\nexport function ProductRecipeTab({ item, onChanged }: { item: Product; onChanged?: () => void }) {\n return <RecipeEditor product={item} onSaved={onChanged} />\n}\n","import React, { useCallback, useEffect, useState } from 'react'\nimport { ArrowDown, ArrowUp, Plus, Trash2 } from 'lucide-react'\nimport {\n Button, Card, CurrencyInput, Input, Skeleton, Switch, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,\n toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { Product, ProductOptionGroup, ProductOptionItem } from '@fayz-ai/inventory/domain/product'\nimport { SaveBarSlot } from './recipe/shared'\n\n// ---------------------------------------------------------------------------\n// Complementos — the choices a product sold carries («Ponto da carne»,\n// «Chantilly»). V1: ProductOptionGroupsManager. Validation is V1's, rule for\n// rule, so a group the till could never satisfy is refused here and not at\n// the counter.\n// ---------------------------------------------------------------------------\n\ntype DraftItem = ProductOptionItem & { key: string }\ntype Draft = Omit<ProductOptionGroup, 'items'> & { key: string; items: DraftItem[] }\n\nlet seq = 0\nconst key = () => `c${++seq}`\nconst newItem = (): DraftItem => ({ key: key(), name: '', priceAdjustment: 0, isActive: true })\nconst newGroup = (): Draft => ({\n key: key(), name: '', isActive: true, isRequired: false, minSelections: 0, maxSelections: 1, items: [newItem()],\n})\n\nconst norm = (v: string) => v.trim().toLocaleLowerCase('pt-BR')\n\nexport function validateOptionGroups(groups: ProductOptionGroup[]): string | null {\n const names = new Set<string>()\n for (const [gi, g] of groups.entries()) {\n const label = g.name.trim() || `Grupo ${gi + 1}`\n if (!norm(g.name)) return `Informe o nome do grupo ${gi + 1}.`\n if (names.has(norm(g.name))) return `O grupo \"${label}\" está duplicado.`\n names.add(norm(g.name))\n if (!Number.isInteger(g.minSelections) || g.minSelections < 0) return `O mínimo de escolhas de \"${label}\" deve ser um número inteiro maior ou igual a zero.`\n if (!Number.isInteger(g.maxSelections) || g.maxSelections < 1) return `O máximo de escolhas de \"${label}\" deve ser um número inteiro maior ou igual a um.`\n if (g.maxSelections < g.minSelections) return `Em \"${label}\", o máximo de escolhas não pode ser menor que o mínimo.`\n if (g.isRequired && g.minSelections < 1) return `O grupo obrigatório \"${label}\" precisa exigir ao menos uma escolha.`\n if (g.items.length === 0) return `Adicione ao menos uma opção ao grupo \"${label}\".`\n if (g.isActive && !g.items.some((i) => i.isActive)) return `Ative ao menos uma opção no grupo \"${label}\".`\n const itemNames = new Set<string>()\n for (const [ii, i] of g.items.entries()) {\n if (!norm(i.name)) return `Informe o nome da opção ${ii + 1} de \"${label}\".`\n if (itemNames.has(norm(i.name))) return `A opção \"${i.name.trim()}\" está duplicada em \"${label}\".`\n itemNames.add(norm(i.name))\n if (!Number.isFinite(i.priceAdjustment) || i.priceAdjustment < 0) return `O acréscimo de \"${i.name.trim()}\" deve ser zero ou um valor positivo.`\n }\n }\n return null\n}\n\nexport function ProductComplementsTab({ item }: { item: Product }) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [groups, setGroups] = useState<Draft[] | null>(null)\n const [dirty, setDirty] = useState(false)\n const [saving, setSaving] = useState(false)\n\n const load = useCallback(async () => {\n const rows = await provider.getProductOptionGroups!(item.id)\n setGroups(rows.map((g) => ({ ...g, key: key(), items: g.items.map((i) => ({ ...i, key: key() })) })))\n setDirty(false)\n }, [provider, item.id])\n\n useEffect(() => {\n load().catch((e) => { toast.error(e instanceof Error ? e.message : t('inventory.complements.loadFailed')); setGroups([]) })\n }, [load, t])\n\n const update = (fn: (gs: Draft[]) => Draft[]) => { setGroups((gs) => fn(gs ?? [])); setDirty(true) }\n const patchGroup = (gk: string, patch: Partial<Draft>) => update((gs) => gs.map((g) => (g.key === gk ? { ...g, ...patch } : g)))\n const patchItem = (gk: string, ik: string, patch: Partial<DraftItem>) =>\n update((gs) => gs.map((g) => (g.key !== gk ? g : { ...g, items: g.items.map((i) => (i.key === ik ? { ...i, ...patch } : i)) })))\n const move = (index: number, dir: -1 | 1) => update((gs) => {\n const to = index + dir\n if (to < 0 || to >= gs.length) return gs\n const next = [...gs];\n [next[index], next[to]] = [next[to], next[index]]\n return next\n })\n\n const save = async () => {\n if (!groups) return\n const error = validateOptionGroups(groups)\n if (error) { toast.error(t('inventory.complements.review'), { description: error }); return }\n setSaving(true)\n try {\n const saved = await provider.saveProductOptionGroups!(item.id, groups)\n setGroups(saved.map((g) => ({ ...g, key: key(), items: g.items.map((i) => ({ ...i, key: key() })) })))\n setDirty(false)\n toast.success(t('inventory.complements.saved'))\n } catch (e) {\n toast.error(t('inventory.complements.saveFailed'), { description: e instanceof Error ? e.message : undefined })\n } finally {\n setSaving(false)\n }\n }\n\n\n if (!groups) {\n return (\n <div className=\"space-y-4\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-96 max-w-full\" />\n <Skeleton className=\"h-32 w-full\" />\n </div>\n )\n }\n\n return (\n <TooltipProvider delayDuration={300}>\n <SaveBarSlot dirty={dirty} saving={saving} onSave={() => { void save() }} onDiscard={() => { void load() }} saveLabel={t('inventory.complements.save')} />\n <div className=\"fz-container space-y-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 className=\"text-base font-semibold\">{t('inventory.complements.title')}</h3>\n <p className=\"mt-1 max-w-2xl text-sm text-muted-foreground\">{t('inventory.complements.hint')}</p>\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => update((gs) => [...gs, newGroup()])}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {t('inventory.complements.newGroup')}\n </Button>\n </div>\n\n {groups.length === 0 && (\n <div className=\"rounded-md border border-dashed px-4 py-10 text-center\">\n <p className=\"text-sm font-medium\">{t('inventory.complements.empty')}</p>\n <p className=\"mt-1 text-sm text-muted-foreground\">{t('inventory.complements.emptyHint')}</p>\n </div>\n )}\n\n {groups.map((g, gi) => (\n <Card key={g.key}>\n <div className=\"space-y-3 p-4\">\n <div className=\"flex flex-wrap items-end gap-3\">\n <label className=\"min-w-[220px] flex-1\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.complements.groupName')}</span>\n <Input value={g.name} onChange={(e) => patchGroup(g.key, { name: e.target.value })} placeholder={t('inventory.complements.groupNamePlaceholder')} />\n </label>\n <label className=\"flex items-center gap-2 pb-2 text-sm\">\n <Switch checked={g.isActive} onCheckedChange={(v) => patchGroup(g.key, { isActive: v })} />\n {t('inventory.complements.active')}\n </label>\n <div className=\"flex items-center pb-0.5\">\n <IconAction label={t('inventory.complements.moveUp')} disabled={gi === 0} onClick={() => move(gi, -1)}><ArrowUp className=\"h-4 w-4\" /></IconAction>\n <IconAction label={t('inventory.complements.moveDown')} disabled={gi === groups.length - 1} onClick={() => move(gi, 1)}><ArrowDown className=\"h-4 w-4\" /></IconAction>\n <IconAction label={t('inventory.complements.deleteGroup')} danger onClick={() => update((gs) => gs.filter((x) => x.key !== g.key))}><Trash2 className=\"h-4 w-4\" /></IconAction>\n </div>\n </div>\n <div className=\"fz-fields grid gap-3 border-t pt-3 md:grid-cols-[minmax(180px,1fr)_140px_140px]\">\n <label className=\"flex items-center gap-2 text-sm\">\n <Switch checked={g.isRequired} onCheckedChange={(v) => patchGroup(g.key, { isRequired: v, minSelections: v ? Math.max(1, g.minSelections) : 0 })} />\n {t('inventory.complements.required')}\n </label>\n <label>\n <span className=\"mb-1 block text-xs font-medium\">{t('inventory.complements.min')}</span>\n <Input type=\"number\" min={g.isRequired ? 1 : 0} step={1} value={g.minSelections} disabled={!g.isRequired}\n onChange={(e) => patchGroup(g.key, { minSelections: Number(e.target.value) })} />\n </label>\n <label>\n <span className=\"mb-1 block text-xs font-medium\">{t('inventory.complements.max')}</span>\n <Input type=\"number\" min={1} step={1} value={g.maxSelections}\n onChange={(e) => patchGroup(g.key, { maxSelections: Number(e.target.value) })} />\n </label>\n </div>\n </div>\n <div className=\"space-y-3 border-t p-4\">\n <div className=\"hidden grid-cols-[minmax(180px,1fr)_160px_90px_40px] gap-3 px-1 text-xs font-medium text-muted-foreground md:grid\">\n <span>{t('inventory.complements.option')}</span><span>{t('inventory.complements.price')}</span><span>{t('inventory.complements.optionActive')}</span><span />\n </div>\n {g.items.map((i) => (\n <div key={i.key} className=\"grid gap-3 rounded-md border p-3 md:grid-cols-[minmax(180px,1fr)_160px_90px_40px] md:items-center md:border-0 md:p-0\">\n <Input value={i.name} onChange={(e) => patchItem(g.key, i.key, { name: e.target.value })} placeholder={t('inventory.complements.optionPlaceholder')} aria-label={t('inventory.complements.option')} />\n <CurrencyInput value={i.priceAdjustment} onChange={(v) => patchItem(g.key, i.key, { priceAdjustment: Number(v) || 0 })} aria-label={t('inventory.complements.price')} />\n <label className=\"flex items-center gap-2 text-sm\">\n <Switch checked={i.isActive} onCheckedChange={(v) => patchItem(g.key, i.key, { isActive: v })} />\n <span className=\"md:sr-only\">{t('inventory.complements.optionActive')}</span>\n </label>\n <IconAction label={t('inventory.complements.deleteOption')} danger onClick={() => patchGroup(g.key, { items: g.items.filter((x) => x.key !== i.key) })}><Trash2 className=\"h-4 w-4\" /></IconAction>\n </div>\n ))}\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => patchGroup(g.key, { items: [...g.items, newItem()] })}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> {t('inventory.complements.addOption')}\n </Button>\n </div>\n </Card>\n ))}\n\n </div>\n </TooltipProvider>\n )\n}\n\nfunction IconAction({ label, onClick, disabled, danger, children }: {\n label: string; onClick: () => void; disabled?: boolean; danger?: boolean; children: React.ReactNode\n}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span>\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" aria-label={label} disabled={disabled} onClick={onClick}\n className={danger ? 'text-destructive hover:text-destructive' : undefined}>\n {children}\n </Button>\n </span>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n )\n}\n","import React, { useRef, useState } from 'react'\nimport { Check, Loader2, Sparkles, Upload, X } from 'lucide-react'\nimport {\n AiActionButton, Button, Checkbox, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, toast,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { Product } from '@fayz-ai/inventory/domain/product'\nimport { TEXTAREA } from './shared'\n\n/** \"Gerar foto com IA\": generate, look, then apply — applying is the only write. */\nexport function GenerateImageDialog({ product, onClose, onApplied }: {\n product: Product\n onClose: () => void\n onApplied: () => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [instructions, setInstructions] = useState('')\n const [useCurrent, setUseCurrent] = useState(!!product.imageUrl)\n const [refs, setRefs] = useState<Array<{ file: File; url: string }>>([])\n const [generating, setGenerating] = useState(false)\n const [applying, setApplying] = useState(false)\n const [image, setImage] = useState<string | null>(null)\n const fileRef = useRef<HTMLInputElement>(null)\n\n const generate = async () => {\n setGenerating(true)\n setImage(null)\n try {\n const referenceUrls: string[] = []\n if (useCurrent && product.imageUrl) referenceUrls.push(product.imageUrl)\n for (const r of refs) referenceUrls.push(await provider.uploadAiReference!(r.file))\n setImage(await provider.generateProductImage!({ productId: product.id, instructions, referenceUrls }))\n } catch (e) {\n toast.error(t('inventory.photoAi.failed'), { description: e instanceof Error ? e.message : undefined })\n } finally {\n setGenerating(false)\n }\n }\n\n const apply = async () => {\n if (!image || !provider.uploadProductImage) return\n setApplying(true)\n try {\n const bytes = Uint8Array.from(atob(image), (c) => c.charCodeAt(0))\n await provider.uploadProductImage(product.id, new File([bytes], `ia-${Date.now()}.png`, { type: 'image/png' }))\n toast.success(t('inventory.photoAi.applied'))\n onApplied()\n onClose()\n } catch (e) {\n toast.error(e instanceof Error ? e.message : t('inventory.photoAi.failed'))\n } finally {\n setApplying(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o && !generating && !applying) onClose() }}>\n <ModalContent size=\"3xl\" className=\"sm:max-h-[90vh]\">\n <ModalHeader>\n <ModalTitle className=\"flex items-center gap-2\"><Sparkles className=\"h-5 w-5 text-primary\" /> {t('inventory.photoAi.title')}</ModalTitle>\n </ModalHeader>\n <ModalBody className=\"min-h-0 flex-1 space-y-5 overflow-y-auto\">\n <div className=\"space-y-1 rounded-lg border bg-muted/30 p-3 text-sm\">\n <div><span className=\"text-muted-foreground\">{t('inventory.photoAi.product')}:</span> <span className=\"font-medium\">{product.name}</span></div>\n {product.categoryName && <div><span className=\"text-muted-foreground\">{t('inventory.photoAi.category')}:</span> {product.categoryName}</div>}\n {product.description && <div className=\"line-clamp-3\"><span className=\"text-muted-foreground\">{t('inventory.sheet.description')}:</span> {product.description}</div>}\n <p className=\"text-xs text-muted-foreground\">{t('inventory.photoAi.usesSheet')}</p>\n </div>\n\n <div className=\"space-y-2\">\n <span className=\"block text-sm font-medium\">{t('inventory.photoAi.references')}</span>\n {product.imageUrl && (\n <label className=\"flex cursor-pointer items-center gap-3 rounded-lg border p-2 hover:bg-muted/40\">\n <Checkbox checked={useCurrent} onChange={setUseCurrent} />\n <img src={product.imageUrl} alt=\"\" className=\"h-12 w-12 rounded object-cover\" />\n <span className=\"text-sm\">{t('inventory.photoAi.useCurrent')}</span>\n </label>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {refs.map((r, i) => (\n <div key={r.url} className=\"relative h-20 w-20 overflow-hidden rounded-lg border\">\n <img src={r.url} alt=\"\" className=\"h-full w-full object-cover\" />\n <Button variant=\"bare\" size=\"bare\" type=\"button\" aria-label={t('inventory.sheet.removePhoto')} className=\"font-normal absolute right-1 top-1 rounded-full bg-background/80 p-0.5\"\n onClick={() => { URL.revokeObjectURL(r.url); setRefs(refs.filter((_, idx) => idx !== i)) }}>\n <X className=\"h-3 w-3\" />\n </Button>\n </div>\n ))}\n {refs.length < 3 && (\n <Button variant=\"bare\" size=\"bare\" type=\"button\" onClick={() => fileRef.current?.click()} aria-label={t('inventory.sheet.addPhoto')}\n className=\"font-normal whitespace-normal flex h-20 w-20 flex-col items-center justify-center rounded-lg border-2 border-dashed text-muted-foreground hover:border-primary/50\">\n <Upload className=\"mb-1 h-4 w-4\" /><span className=\"text-[10px]\">{t('inventory.photoAi.add')}</span>\n </Button>\n )}\n <input ref={fileRef} type=\"file\" accept=\"image/*\" multiple className=\"hidden\" onChange={(e) => {\n const files = Array.from(e.target.files ?? []).slice(0, 3 - refs.length)\n setRefs((xs) => [...xs, ...files.map((file) => ({ file, url: URL.createObjectURL(file) }))])\n e.target.value = ''\n }} />\n </div>\n </div>\n\n <label className=\"block\">\n <span className=\"mb-1 block text-sm font-medium\">{t('inventory.sheet.aiInstructions')}</span>\n <textarea className={TEXTAREA} rows={3} value={instructions} onChange={(e) => setInstructions(e.target.value)} placeholder={t('inventory.photoAi.instructionsPlaceholder')} />\n </label>\n\n {(generating || image) && (\n <div className=\"flex justify-center rounded-lg border bg-muted/20 p-3\">\n {generating\n ? <div className=\"flex h-64 w-64 flex-col items-center justify-center gap-2 text-sm text-muted-foreground\"><Loader2 className=\"h-6 w-6 animate-spin\" />{t('inventory.photoAi.generating')}</div>\n : <img src={`data:image/png;base64,${image}`} alt=\"\" className=\"max-h-80 rounded-md\" />}\n </div>\n )}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={generating || applying}>{t('common.cancel')}</Button>\n <AiActionButton tone={image ? 'soft' : 'solid'} onClick={() => void generate()} busy={generating} disabled={applying}>\n {image ? t('inventory.photoAi.again') : t('inventory.photoAi.generate')}\n </AiActionButton>\n {image && (\n <Button onClick={() => void apply()} disabled={applying}>\n {applying ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : <Check className=\"mr-2 h-4 w-4\" />}{t('inventory.photoAi.apply')}\n </Button>\n )}\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { Package } from 'lucide-react'\nimport { CrudDetailPage } from '@fayz-ai/admin'\nimport { useHasMenu, useHasRecipes } from './useHasMenu'\nimport { Button, SubpageHeader } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { DetailTab, EntityDef } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider } from '../context'\nimport type { Product } from '@fayz-ai/inventory/domain/product'\nimport { buildProductEntity } from './productEntity'\nimport { flattenProduct, unflattenProduct } from './productFichas'\nimport { ProductRecipeTab } from './ProductRecipeTab'\nimport { ProductComplementsTab } from './ProductComplementsTab'\nimport { GenerateImageDialog } from './recipe/GenerateImageDialog'\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/**\n * The product's tabs, in order. One answer for the page and for the edit form,\n * which draws the same strip.\n *\n * Each tab opens with its switch, as in V1: Complementos with «Venda», Ficha\n * Técnica with «Produto produzido». The sheet also opens when asked for by\n * route — «Nova Ficha Técnica» may pick a product not yet produced.\n */\nexport function productRecordTabs({ entity, flat, hasMenu, hasRecipes, withComplements, initialTab, contributedTabs, t, reload }: {\n entity: EntityDef\n flat: Record<string, any> | null\n hasMenu: boolean\n hasRecipes: boolean\n withComplements: boolean\n initialTab?: string\n contributedTabs: DetailTab[]\n t: (key: string) => string\n reload?: () => void\n}): DetailTab[] {\n const extra: DetailTab[] = []\n if (hasMenu && flat?.isForSale && withComplements) {\n extra.push({ id: 'complements', label: t('inventory.complements.tab'), icon: 'ListPlus', component: ProductComplementsTab as never })\n }\n if (hasRecipes && (flat?.isProduced || initialTab === 'recipe')) {\n extra.push({ id: 'recipe', label: t('inventory.productRecipe.tab'), icon: 'ChefHat', component: ProductRecipeTab as never, props: { onChanged: reload } })\n }\n const tabs = entity.detailTabs ?? []\n const stockAt = tabs.findIndex((tab) => tab.id === 'stock')\n const own = stockAt < 0 ? [...tabs, ...extra] : [...tabs.slice(0, stockAt), ...extra, ...tabs.slice(stockAt)]\n return [...own, ...contributedTabs]\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, productDetailTabs: contributedTabs } = 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 hasMenu = useHasMenu()\n const hasRecipes = useHasRecipes()\n const entity = useMemo(\n () => buildProductEntity(t, productTypes, currency, reload, undefined, true, hasMenu, hasRecipes),\n [t, productTypes, currency, reload, hasMenu, hasRecipes],\n )\n\n // A ficha lê o MESMO registro plano que o formulário edita. Sem isto as abas\n // das fichas nunca apareciam aqui: `visibleWhen` pergunta por `isForSale`, e\n // o produto do domínio guarda isso em `classification.isForSale` — a\n // pergunta voltava `undefined` e a aba inteira sumia em silêncio.\n const flat = useMemo(\n () => (product ? flattenProduct(product as unknown as Record<string, any>) : null),\n [product],\n )\n\n // A ficha do produto edita no lugar, como a do cliente. Era a mesma peça\n // genérica dos dois lados e só faltava este sinal: sem `onFieldsSave`, o\n // `CrudDetailPage` entende \"somente leitura\" e nem desenha o lápis — então\n // trocar um preço obrigava a abrir o formulário inteiro.\n //\n // Os campos chegam PLANOS (é o que a ficha desenha) e voltam para as fichas\n // pelo mesmo caminho do formulário: uma escrita só para os campos encostados.\n const saveFields = useCallback(async (values: Record<string, unknown>) => {\n // O registro inteiro com o que foi encostado por cima — ver `unflattenProduct`.\n await provider.updateProduct(productId, unflattenProduct({ ...(flat ?? {}), ...values }) as Partial<Product>)\n reload()\n }, [provider, productId, reload, flat])\n\n const [photoOpen, setPhotoOpen] = useState(false)\n\n // Each tab opens with its switch, as in V1: Complementos with «Venda»,\n // Ficha Técnica with «Produto produzido». The sheet also opens when asked\n // for by route — «Nova Ficha Técnica» may pick a product not yet produced,\n // and saving the sheet is what turns the switch on.\n const entityForDetail = useMemo(() => {\n const detailTabs = productRecordTabs({ entity, flat, hasMenu, hasRecipes, withComplements: Boolean(provider.getProductOptionGroups), initialTab, contributedTabs, t, reload })\n return {\n ...entity,\n detailTabs,\n detailActions: [\n ...(entity.detailActions ?? []),\n ...(provider.generateProductImage && provider.uploadProductImage\n ? [{ id: 'photo-ai', label: t('inventory.photoAi.title'), icon: 'Sparkles', intent: 'secondary' as const, run: () => { setPhotoOpen(true) } }]\n : []),\n ],\n }\n }, [entity, hasMenu, hasRecipes, flat?.isForSale, flat?.isProduced, initialTab, provider, reload, t, contributedTabs])\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 variant=\"bare\" size=\"bare\" onClick={onBack} className=\"font-normal 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 <>\n <CrudDetailPage\n entityDef={entityForDetail}\n onFieldsSave={saveFields}\n // O produto primeiro (traz saldo, categoria, carimbos), o plano por cima:\n // é ele que responde `isForSale` e companhia.\n item={{ ...(product as unknown as Record<string, any>), ...(flat ?? {}) }}\n namePlural={t('inventory.nav.products')}\n basePath=\"/inventory/products\"\n initialTab={initialTab}\n onBack={onBack}\n onEdit={onEdit}\n feature=\"inventory\"\n />\n {photoOpen && <GenerateImageDialog product={product} onClose={() => setPhotoOpen(false)} onApplied={reload} />}\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 '@fayz-ai/inventory/domain/product'\nimport { buildProductEntity } from './productEntity'\nimport { productRecordTabs } from './ProductDetailView'\nimport { useHasMenu, useHasRecipes } from './useHasMenu'\nimport { SALE_CHANNELS, channelFieldKey, flattenProduct, toFichas } from './productFichas'\nimport { createIdempotencyKey } from '@fayz-ai/inventory/lib/idempotency'\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\n\nexport function ProductCrudForm({ editId, onSaved, onOpenTab }: {\n editId?: string\n onSaved?: () => void\n /** Edit mode shows the product's tab strip; called for a tab the form does not hold. */\n onOpenTab?: (tabId: string) => void\n}) {\n const t = useTranslation()\n const { productTypes, currency, productDetailTabs: contributedTabs } = 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(p ? flattenProduct(p as unknown as Record<string, any>) : {})\n })()\n return () => { cancelled = true }\n }, [editId])\n\n const hasMenu = useHasMenu()\n const hasRecipes = useHasRecipes()\n const entity = React.useMemo(\n () => buildProductEntity(t, productTypes, currency, undefined, provider, true, hasMenu, hasRecipes),\n [t, productTypes, currency, provider, hasMenu, hasRecipes],\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 classification = {\n isIngredient: values.isIngredient === true,\n isForSale: values.isForSale === true,\n isIntermediate: values.isIntermediate === true,\n isAsset: values.isAsset === true,\n isProduced: values.isProduced === true,\n isResale: values.isResale === true,\n trackByUnitLabel: values.trackByUnitLabel === true,\n }\n // Nenhum interruptor ligado seria um produto sem ficha nenhuma — e sem\n // lugar na lista, porque a faceta lê o tipo derivado. O V1 marca a\n // Classificação como obrigatória pelo mesmo motivo.\n if (!Object.values(classification).some(Boolean)) {\n toast.error(t('inventory.productForm.classificationRequired'))\n throw new Error('classification required')\n }\n const productType = (values.productType ?? productTypes[0]?.value) as ProductType\n const payload = {\n classification,\n extras: {\n commissionPercent: Number(values.commissionPercent) || 0,\n chartAccountId: values.chartAccountId ?? '',\n contentPerUnit: values.contentPerUnit === '' ? undefined : Number(values.contentPerUnit) || undefined,\n contentUnitId: values.contentUnitId ?? '',\n avgPurchasePrice: Number(values.avgPurchasePrice) || undefined,\n professionalResalePrice: Number(values.professionalResalePrice) || undefined,\n requireBatchForStock: values.requireBatchForStock === true,\n requireExpiryForStock: values.requireExpiryForStock === true,\n },\n ...toFichas(values),\n purchaseUnitId: values.purchaseUnitId ?? '',\n conversionFactor: Number(values.conversionFactor) || 1,\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: classification.isForSale ? (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 const openingQty = Number(values._initialQty) || 0\n if (openingQty > 0) {\n try {\n await provider.createMovement({\n productId: created.id,\n movementType: 'entry',\n quantity: openingQty,\n unitCost: Number(values._initialUnitCost) || Number(values.costPrice) || undefined,\n stockLocationId: values._initialLocationId || values.defaultLocationId || undefined,\n batchNumber: values._initialBatch || undefined,\n expirationDate: values._initialExpiry || undefined,\n idempotencyKey: createIdempotencyKey('opening-stock'),\n })\n } catch (error) {\n // Same reasoning as the photo: the product exists, so a retry here\n // would duplicate it. Point at the Stock tab instead.\n toast.error(t('inventory.productForm.initialEntryFailed'), { description: errorMessage(error) })\n }\n }\n }\n onSaved?.()\n }\n\n // Same strip as the product's page, so the tabs do not move between reading and editing.\n const formEntity = React.useMemo(() => {\n if (!isEdit || !initialData) return entity\n return {\n ...entity,\n detailTabs: productRecordTabs({ entity, flat: initialData, hasMenu, hasRecipes, withComplements: Boolean(provider.getProductOptionGroups), contributedTabs, t }),\n }\n }, [entity, isEdit, initialData, hasMenu, hasRecipes, provider, contributedTabs, t])\n const ready = Boolean(initialData) && referenceDataReady\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 {/* In edit mode the form draws the record's own header (name, status,\n Cancel) and tab strip; this one covers create and the loading gap. */}\n {(!isEdit || !ready) && (\n <SubpageHeader title={title} subtitle={subtitle} onBack={onSaved} parentLabel={t('inventory.nav.products')} />\n )}\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 {!ready && <CrudFormSkeleton twoColumn tabs={isEdit} />}\n {ready && (\n <CrudFormPage\n entityDef={formEntity}\n mode={isEdit ? 'edit' : 'create'}\n initialData={initialData!}\n onSubmit={save}\n onCancel={() => onSaved?.()}\n namePlural={t('inventory.nav.products')}\n hideBreadcrumb={!isEdit}\n onRecordTab={isEdit ? onOpenTab : undefined}\n />\n )}\n </div>\n )\n}\n","import React, { useState, useEffect, useMemo, useRef } 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 { Button, cn, Input, Textarea } from '@fayz-ai/ui'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport { createPendingCommand, useTranslation } from '@fayz-ai/core'\nimport { SearchSelect, type SearchSelectOption } from '@fayz-ai/ui'\nimport { DatePicker } from '@fayz-ai/ui'\nimport {\n MOVEMENT_TYPE_VALUES, canRecordMovement, movementNeedsDestination, movementNeedsReason, movementTakesSupplier,\n type CreateStockMovementInput, type MovementType, type StockMovement,\n} from '@fayz-ai/inventory/domain/movement'\nimport type { StockPosition } from '@fayz-ai/inventory/domain/stock'\nimport type { Supplier } from '@fayz-ai/inventory/domain/product'\nimport { createIdempotencyKey } from '@fayz-ai/inventory/lib/idempotency'\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 const command = useRef(createPendingCommand<CreateStockMovementInput>(() => createIdempotencyKey('inventory:manual-movement'), (input) => input.productId))\n const [pending, setPending] = useState(false)\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 = movementNeedsReason(movementType)\n const needsDest = movementNeedsDestination(movementType)\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 = canRecordMovement({ movementType, quantity, reason, destinationLocationId: 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 (command.current.running || (!command.current.pending && (!productId || quantity <= 0))) return\n setSaving(true)\n setPending(true)\n try {\n const movement = await command.current.run({\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: movementTakesSupplier(movementType) ? supplierId || undefined : undefined,\n }, createMovement)\n setSavedMovement(movement)\n } catch {\n // The store reports the failure; retain the immutable attempt for retry.\n } finally {\n setSaving(false)\n setPending(command.current.pending)\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={() => { if (!command.current.pending && !command.current.running) { if (step > 1) setStep(step - 1); else 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 variant=\"bare\" size=\"bare\"\n key={mt.value}\n onClick={() => setMovementType(mt.value)}\n className={`block whitespace-normal rounded-lg border-2 p-3 text-left font-normal 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 data-tour=\"inventory.entry-product\"\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 variant=\"bare\" size=\"bare\"\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=\"mt-1\"\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 <div className=\"flex-1\">\n <Input type=\"number\" min={0} step={0.01} value={unitCost} onChange={(e) => setUnitCost(Number(e.target.value) || 0)} className=\"h-auto rounded-none border-0 bg-transparent p-2 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0\" />\n </div>\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 variant=\"bare\" size=\"bare\"\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 variant=\"bare\" size=\"bare\"\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=\"mt-1\" />\n </div>\n )}\n </div>\n\n <div className=\"flex justify-between\">\n <Button variant=\"bare\" size=\"bare\" 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 variant=\"bare\" size=\"bare\" 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 {pending && <p role=\"status\" className=\"text-sm text-warning\">{t('inventory.stock.pendingRetry')}</p>}\n <fieldset disabled={pending} 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=\"mt-1\" />\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=\"mt-1\" />\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=\"mt-1 resize-none\" />\n </div>\n </fieldset>\n\n <div className=\"flex justify-between\">\n <Button variant=\"bare\" size=\"bare\" disabled={pending} onClick={() => { if (!command.current.pending) 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 variant=\"bare\" size=\"bare\"\n data-tour=\"inventory.entry-save\"\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, { useCallback, useEffect, useState, useMemo } from 'react'\nimport { ArrowUpRight, ArrowDownRight, RefreshCw, ArrowRightLeft, Trash2, CircleDashed, MapPin } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ListView, Button, DatePicker, FilterMenuRow, FilterPanel, FilterPanelField, InlineLink, Modal, ModalContent, RequiredFilter } from '@fayz-ai/ui'\nimport { resolveDocumentOpenerFor } from '@fayz-ai/admin'\nimport { useInventoryStore, formatCurrency, useInventoryConfig } from '../context'\nimport { useTranslation } from '@fayz-ai/core'\nimport { SubpageHeader } from '@fayz-ai/ui'\nimport {\n MOVEMENT_TYPES, movementTypeSpec, normalizeMovementType, type MovementType, type StockMovement,\n} from '@fayz-ai/inventory/domain/movement'\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\n/** `03/09/2026 às 10:53` — a data com hora, como o V1 escreve. */\nfunction dataHora(iso: string | undefined): string {\n if (!iso) return '—'\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso.slice(0, 10).split('-').reverse().join('/')\n // Meia-noite em ponto quase sempre é data SEM hora, e «às 00:00» finge uma\n // precisão que o dado não tem.\n const hora = d.getHours() === 0 && d.getMinutes() === 0\n ? ''\n : ` às ${d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}`\n return `${d.toLocaleDateString('pt-BR')}${hora}`\n}\n\n/** Um campo rotulado do cartão: rótulo pequeno em cima, valor embaixo. */\nfunction Field({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"min-w-0\">\n <dt className=\"text-xs text-muted-foreground\">{label}</dt>\n <dd className=\"truncate\">{children}</dd>\n </div>\n )\n}\n\n/**\n * A COR DIZ A DIREÇÃO, e é a primeira coisa que se lê no cartão.\n *\n * O V1 pinta a pílula INTEIRA — fundo verde-claro com texto verde-escuro — e não\n * só a letra. Com fundo neutro e texto colorido, entrada e saída pareciam a mesma\n * coisa até alguém ler a palavra; a cor existe justamente para não precisar ler.\n *\n * Verde entra, vermelho sai. Perda também diminui o saldo, mas é AMARELO de\n * propósito: saída é mercadoria que serviu para alguma coisa e perda é mercadoria\n * que não serviu, e pintá-las igual apagaria a única diferença que importa quando\n * alguém procura por onde o estoque está vazando.\n */\nconst TYPE_COLORS: Record<MovementType, string> = {\n entry: 'bg-success-soft text-success-soft-foreground',\n exit: 'bg-destructive-soft text-destructive-soft-foreground',\n adjustment: 'bg-info-soft text-info-soft-foreground',\n transfer: 'bg-magic-soft text-magic-soft-foreground',\n loss: 'bg-warning-soft text-warning-soft-foreground',\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, documentModal } = useInventoryConfig()\n // O documento aberto por cima da lista. A lista NÃO é desmontada: quem fecha\n // volta ao mesmo recorte, à mesma busca e à mesma rolagem.\n const [documento, setDocumento] = useState<StockMovement | null>(null)\n const movements = useInventoryStore((s) => s.movements)\n const movementsLoading = useInventoryStore((s) => s.movementsLoading)\n const fetchMovements = useInventoryStore((s) => s.fetchMovements)\n\n const locations = useInventoryStore((s) => s.locations)\n const fetchLocations = useInventoryStore((s) => s.fetchLocations)\n useEffect(() => { void fetchLocations() }, [fetchLocations])\n\n const [search, setSearch] = useState('')\n\n // ── O RECORTE DO V1, e ele so busca quando mandam ────────────────────────\n //\n // O razao do V1 recorta por tipo, periodo e local, e a lista aqui nao\n // recortava por nada: «o que saiu de Cozinha em setembro?» nao tinha\n // resposta, e a unica saida era rolar o razao inteiro.\n //\n // Rascunho, como nas telas do financeiro: cada campo custa uma leitura do\n // razao, e mexer em tres deles nao pode custar tres.\n const hoje = () => {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n }\n const trintaDiasAtras = useMemo(() => {\n const d = new Date(); d.setDate(d.getDate() - 29)\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n }, [])\n const [tipos, setTipos] = useState<MovementType[]>([])\n const [locationId, setLocationId] = useState('')\n const [dateFrom, setDateFrom] = useState(trintaDiasAtras)\n const [dateTo, setDateTo] = useState(hoje)\n\n const rascunho = useMemo(\n () => ({ tipos, locationId, from: dateFrom, to: dateTo }),\n [tipos, locationId, dateFrom, dateTo],\n )\n const [emVigor, setEmVigor] = useState(rascunho)\n const filtrosPendentes = useMemo(\n () => JSON.stringify(rascunho) !== JSON.stringify(emVigor),\n [rascunho, emVigor],\n )\n const aplicarFiltros = useCallback(() => setEmVigor(() => rascunho), [rascunho])\n const limparFiltros = () => {\n setTipos([])\n setLocationId('')\n setDateFrom(trintaDiasAtras)\n setDateTo(hoje())\n }\n\n useEffect(() => {\n fetchMovements({\n search: search || undefined,\n movementType: emVigor.tipos.length > 0 ? emVigor.tipos : undefined,\n stockLocationId: emVigor.locationId || undefined,\n dateRange: { from: emVigor.from, to: emVigor.to },\n })\n }, [search, emVigor])\n\n // ---------------------------------------------------------------------------\n // UM CARTÃO POR MOVIMENTO, como no V1.\n // ---------------------------------------------------------------------------\n // A tela do V1 (Estoque → Movimentações) não é tabela: cada movimento é um\n // cartão que começa pelo TIPO, porque o tipo é a informação mais importante da\n // linha, e termina em «Motivo:», porque nenhum movimento existe sem motivo.\n //\n // A tabela que estava aqui espalhava isso em seis colunas estreitas, e o motivo\n // — que responde «de onde vieram essas entradas que eu não lancei?» — virava\n // legenda truncada debaixo do nome do produto.\n //\n // O que o V1 NÃO tem e fica: o LOCAL de estoque. Copiar a forma não é motivo\n // para perder um dado que a V2 já mostrava.\n //\n // Continua dentro do `ListView` — UMA coluna, sem cabeçalho. A busca, o «Nova\n // Movimentação», o estado vazio e os filtros são os mesmos de toda lista do\n // produto; só o desenho da linha muda.\n const columns: ColumnDef<StockMovement, any>[] = useMemo(() => [\n {\n id: 'movimento',\n header: () => null,\n cell: ({ row }: any) => {\n const m = row.original as StockMovement\n // O RAZÃO FALA OUTRA PALAVRA. A view devolve `kind` como `movement_type`,\n // e lá a entrada se chama `in`, não `entry`. O rótulo já normalizava (por\n // isso escrevia «Entrada»), mas os mapas de ícone e cor eram indexados\n // pelo nome canônico — então toda entrada caía no padrão e saía cinza,\n // com o ícone de «atualizar». Normaliza UMA vez, no topo da célula.\n const type = normalizeMovementType(m.movementType) ?? m.movementType\n const Icon = TYPE_ICONS[type] ?? RefreshCw\n const reason: string | undefined = m.reason || undefined\n const doc: string | undefined = m.documentNumber || undefined\n // Um uuid não é número de documento para ninguém: quando a origem é o\n // próprio sistema (a venda que consumiu a receita), o id não vira texto\n // de tela. Melhor não dizer nada do que dizer um uuid.\n const printableDoc = doc && !/^[0-9a-f-]{32,36}$/i.test(doc) ? doc : undefined\n const caption = reason ?? (printableDoc ? `Documento ${printableDoc}` : undefined)\n // O CAMINHO DE VOLTA. A linha sabe que veio de um documento e de QUAL\n // operação; quem sabe desenhá-lo se registrou ao ser carregado. A\n // configuração do app ainda ganha, para o caso de ele querer outra coisa.\n const abrivel = Boolean(documentModal || resolveDocumentOpenerFor(m))\n const total = Number(m.totalCost)\n const temTotal = Number.isFinite(total) && total !== 0\n\n return (\n <div className=\"space-y-3 py-1\">\n {/* ① Tipo e produto, nesta ordem — é como o V1 abre o cartão. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className={`inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${TYPE_COLORS[type] ?? 'bg-muted text-muted-foreground'}`}>\n <Icon className=\"h-3 w-3\" aria-hidden />\n {movementTypeLabel(type, t)}\n </span>\n <span className=\"min-w-0 truncate font-semibold\">{m.productName ?? '—'}</span>\n </div>\n\n {/* ② Os campos rotulados. O V1 põe três; o Local entra como quarto\n quando existe, porque perder dado não faz parte de copiar forma. */}\n <dl className=\"grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2 lg:grid-cols-4\">\n <Field label={t('inventory.history.columnQty')}>\n <span className=\"font-medium tabular-nums\">\n {signedQuantity(m.quantity)}\n {m.measurementUnitAbbreviation && (\n <span className=\"ml-1 uppercase text-muted-foreground\">{m.measurementUnitAbbreviation}</span>\n )}\n </span>\n </Field>\n <Field label={t('inventory.history.columnDate')}>\n <span className=\"tabular-nums\">{dataHora(m.movementDate)}</span>\n </Field>\n <Field label={t('inventory.history.columnTotal')}>\n {temTotal ? (\n <span className=\"font-medium tabular-nums\">{formatCurrency(total, currency)}</span>\n ) : (\n // Custo é OPCIONAL na entrada, e o V1 documenta o beco que isso\n // abre: o saldo sobe, o valor do estoque não, e o «Valor Total»\n // da visão geral se descola sem ninguém errar nada. «R$ 0,00»\n // esconderia isso atrás de um número.\n <span\n className=\"text-muted-foreground\"\n title=\"Movimento registrado sem custo: o saldo mudou, o valor do estoque não\"\n >\n —\n </span>\n )}\n </Field>\n {m.stockLocationName && (\n <Field label={t('inventory.history.columnLocation')}>\n <span className=\"truncate\">\n {m.stockLocationName}\n {type === 'transfer' && m.destinationLocationName && <> → {m.destinationLocationName}</>}\n </span>\n </Field>\n )}\n </dl>\n\n {/* ③ O motivo, por último e por extenso. É o fecho do cartão do V1. */}\n <p className=\"text-sm\">\n <span className=\"text-muted-foreground\">Motivo: </span>\n {caption ? (\n abrivel ? (\n // `dashed` e não `solid`: o tracejado é o traço que este produto\n // usa para «esta palavra é um gatilho» — o mesmo da data no\n // cronograma de pagamento e dos controles da barra. Contínuo\n // promete navegação, e aqui nada sai da página.\n //\n // Sem a seta de link externo, pela mesma razão: ela diz «isto te\n // leva embora», e o que acontece é um modal por cima da lista,\n // com a lista intacta atrás.\n <InlineLink\n tone=\"dashed\"\n title={`Abrir ${caption}`}\n // A linha inteira abre o detalhe do movimento; este gatilho abre\n // o DOCUMENTO. Sem parar a propagação, um clique faria as duas.\n onClick={(e) => { e.stopPropagation(); setDocumento(m) }}\n >\n {caption}\n </InlineLink>\n ) : caption\n ) : (\n // Movimento sem motivo é um buraco no razão, e o V1 não deixa\n // criar um pela tela. Dizê-lo é o que faz alguém parar de criar.\n <span className=\"italic text-muted-foreground\">sem motivo registrado</span>\n )}\n </p>\n </div>\n )\n },\n },\n ], [currency, t, documentModal])\n\n return (\n <div className=\"space-y-4\">\n <SubpageHeader title={t('inventory.history.title')} subtitle={t('inventory.history.subtitle')} />\n\n <FilterPanel\n title={t('inventory.filters.title')}\n dirty={filtrosPendentes}\n onApply={aplicarFiltros}\n applyLabel={t('inventory.filters.apply')}\n pendingTitle={t('inventory.filters.pending')}\n pendingHint={t('inventory.filters.pendingHint')}\n onClear={(tipos.length > 0 || locationId) ? limparFiltros : undefined}\n clearLabel={t('inventory.filters.clear')}\n busy={movementsLoading}\n >\n <FilterPanelField label={t('inventory.history.columnType')}>\n <RequiredFilter\n label={t('inventory.history.columnType')}\n value={\n tipos.length === 0\n ? t('inventory.filters.allTypes')\n : tipos.length === 1\n ? movementTypeLabel(tipos[0], t)\n : t('crud.list.selectedMany', { count: tipos.length })\n }\n icon={CircleDashed}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n <div className=\"space-y-0.5\">\n <FilterMenuRow active={tipos.length === 0} onClick={() => setTipos([])}>\n {t('inventory.filters.allTypes')}\n </FilterMenuRow>\n {MOVEMENT_TYPES.map((spec) => {\n const on = tipos.includes(spec.value)\n return (\n <FilterMenuRow\n key={spec.value}\n active={on}\n onClick={() => setTipos(on ? tipos.filter((v) => v !== spec.value) : [...tipos, spec.value])}\n >\n <span className=\"truncate\">{t(spec.labelKey)}</span>\n </FilterMenuRow>\n )\n })}\n </div>\n </RequiredFilter>\n </FilterPanelField>\n\n {locations.length > 0 && (\n <FilterPanelField label={t('inventory.filters.location')}>\n <RequiredFilter\n label={t('inventory.filters.location')}\n value={locations.find((l) => l.id === locationId)?.name ?? t('inventory.filters.allLocations')}\n icon={MapPin}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!locationId} onClick={() => { setLocationId(''); close() }}>\n {t('inventory.filters.allLocations')}\n </FilterMenuRow>\n {locations.map((l) => (\n <FilterMenuRow key={l.id} active={locationId === l.id} onClick={() => { setLocationId(l.id); close() }}>\n <span className=\"truncate\">{l.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n\n <FilterPanelField label={t('inventory.filters.from')}>\n <DatePicker variant=\"input\" format=\"numeric\" className=\"w-full\" value={dateFrom} onChange={(v) => v && setDateFrom(v)} />\n </FilterPanelField>\n <FilterPanelField label={t('inventory.filters.to')}>\n <DatePicker variant=\"input\" format=\"numeric\" className=\"w-full\" value={dateTo} onChange={(v) => v && setDateTo(v)} />\n </FilterPanelField>\n </FilterPanel>\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\n {/* O documento que originou o movimento. O Estoque desenha a moldura e\n cuida do abrir/fechar; o conteúdo vem de quem sabe o que é uma NF-e. */}\n <Modal open={Boolean(documento)} onOpenChange={(open) => { if (!open) setDocumento(null) }}>\n {documento && (\n <ModalContent size=\"5xl\" noPadding className=\"sm:max-h-[90vh]\">\n {documentModal\n ? documentModal(documento, () => setDocumento(null))\n : resolveDocumentOpenerFor(documento)?.render(documento, () => setDocumento(null))}\n </ModalContent>\n )}\n </Modal>\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CircleDashed, Layers, MapPin, Search, Boxes } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport {\n Button,\n Card, DataTable, FilterMenuRow, FilterPanel, FilterPanelField, Input, RequiredFilter, SegmentedControl,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, useInventoryStore, formatCurrency } from '../context'\nimport type { ProductCategory } from '@fayz-ai/inventory/domain/product'\nimport type { StockHealth, StockPanelRow } from '@fayz-ai/inventory/domain/stock'\n\n// ---------------------------------------------------------------------------\n// O PAINEL DO INVENTÁRIO — quanto há, onde, de que lote e até quando.\n//\n// É a primeira das duas abas do inventário do V1 (Painel · Contagens), e a que\n// não existia aqui: o inventário abria direto na lista de contagens, que\n// responde \"o que já foi conferido\" e não \"o que eu tenho\".\n//\n// UMA LINHA POR POSIÇÃO (produto × local × lote × validade), e não por produto:\n// somado, um lote vencido desaparece dentro de um saldo saudável — e o painel\n// existe justamente para que ele não desapareça.\n//\n// O que o V1 tem e esta tela ainda não: curva ABC e giro de 90 dias. Os dois\n// são análise sobre o histórico de saída, não um campo da posição; entram\n// quando houver de onde calculá-los.\n// ---------------------------------------------------------------------------\n\nconst HEALTH_ORDER: readonly StockHealth[] = ['negative', 'below_min', 'zero', 'ok']\n\nconst HEALTH_TONE: Record<StockHealth, string> = {\n negative: 'bg-destructive-soft text-destructive-soft-foreground',\n below_min: 'bg-warning-soft text-warning-soft-foreground',\n zero: 'bg-muted text-muted-foreground',\n ok: 'bg-success-soft text-success-soft-foreground',\n}\n\nconst EXPIRY_OPTIONS = ['all', 'expired', 'le30', 'le60', 'le90', 'none'] as const\ntype ExpiryFilter = (typeof EXPIRY_OPTIONS)[number]\n\nexport function StockPanelView() {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const { currency } = useInventoryConfig()\n const locations = useInventoryStore((s) => s.locations)\n const fetchLocations = useInventoryStore((s) => s.fetchLocations)\n\n const [categories, setCategories] = useState<ProductCategory[]>([])\n const [rows, setRows] = useState<StockPanelRow[]>([])\n const [loading, setLoading] = useState(false)\n const [suportado, setSuportado] = useState(true)\n\n useEffect(() => { void fetchLocations() }, [fetchLocations])\n useEffect(() => {\n let vivo = true\n provider.getCategories().then((c) => { if (vivo) setCategories(c) }).catch(() => {})\n return () => { vivo = false }\n }, [provider])\n\n // ── O rascunho e o recorte em vigor ─────────────────────────────────────\n //\n // O painel do V1 tem «Aplicar filtros» e não recarrega a cada campo — e com\n // razão: são seis recortes, e a consulta varre as posições do inquilino.\n const [locationId, setLocationId] = useState('')\n const [categoryId, setCategoryId] = useState('')\n const [produto, setProduto] = useState('')\n const [lote, setLote] = useState('')\n const [validade, setValidade] = useState<ExpiryFilter>('all')\n const [saude, setSaude] = useState<StockHealth[]>([])\n\n const rascunho = useMemo(\n () => ({ locationId, categoryId, produto: produto.trim(), lote: lote.trim(), validade, saude }),\n [locationId, categoryId, produto, lote, validade, saude],\n )\n const [emVigor, setEmVigor] = useState(rascunho)\n const filtrosPendentes = useMemo(\n () => JSON.stringify(rascunho) !== JSON.stringify(emVigor),\n [rascunho, emVigor],\n )\n const aplicarFiltros = useCallback(() => setEmVigor(() => rascunho), [rascunho])\n const limparFiltros = () => {\n setLocationId(''); setCategoryId(''); setProduto(''); setLote('')\n setValidade('all'); setSaude([])\n }\n const filtrosAtivos =\n (locationId ? 1 : 0) + (categoryId ? 1 : 0) + (produto.trim() ? 1 : 0) +\n (lote.trim() ? 1 : 0) + (validade !== 'all' ? 1 : 0) + (saude.length > 0 ? 1 : 0)\n\n useEffect(() => {\n if (!provider.getStockPanel) { setSuportado(false); return }\n let vivo = true\n setLoading(true)\n provider.getStockPanel({\n stockLocationId: emVigor.locationId || undefined,\n categoryId: emVigor.categoryId || undefined,\n productSearch: emVigor.produto || undefined,\n batch: emVigor.lote || undefined,\n expiry: emVigor.validade,\n status: emVigor.saude.length > 0 ? emVigor.saude : undefined,\n })\n .then((data) => { if (vivo) setRows(data) })\n .catch(() => { if (vivo) setRows([]) })\n .finally(() => { if (vivo) setLoading(false) })\n return () => { vivo = false }\n }, [provider, emVigor])\n\n const totais = useMemo(() => ({\n linhas: rows.length,\n valor: rows.reduce((soma, r) => soma + r.totalValue, 0),\n }), [rows])\n\n const columns: ColumnDef<StockPanelRow, any>[] = useMemo(() => [\n {\n accessorKey: 'productName', header: t('inventory.panel.columnProduct'),\n cell: ({ row }) => (\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{row.original.productName}</p>\n {row.original.categoryName && (\n <p className=\"truncate text-[10px] text-muted-foreground\">{row.original.categoryName}</p>\n )}\n </div>\n ),\n },\n {\n accessorKey: 'stockLocationName', header: t('inventory.panel.columnLocation'),\n cell: ({ getValue }) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'batchNumber', header: t('inventory.panel.columnBatch'),\n cell: ({ getValue }) => <span className=\"font-mono text-xs text-muted-foreground\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'expirationDate', header: t('inventory.panel.columnExpiry'),\n cell: ({ getValue }) => <span className=\"text-xs text-muted-foreground\">{(getValue() as string) ?? '—'}</span>,\n },\n {\n accessorKey: 'quantity', header: t('inventory.panel.columnQuantity'), enableSorting: true,\n cell: ({ row }) => (\n <span className=\"block text-right tabular-nums\">\n {row.original.quantity}\n {row.original.minQuantity > 0 && (\n <span className=\"ml-1 text-[10px] text-muted-foreground\">/ {row.original.minQuantity}</span>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'totalValue', header: t('inventory.panel.columnValue'), enableSorting: true,\n cell: ({ getValue }) => (\n <span className=\"block text-right tabular-nums\">{formatCurrency(Number(getValue()) || 0, currency)}</span>\n ),\n },\n {\n accessorKey: 'health', header: t('inventory.filters.stockState'),\n cell: ({ getValue }) => {\n const h = getValue() as StockHealth\n return (\n <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium ${HEALTH_TONE[h]}`}>\n {t(`inventory.filters.health.${h}`)}\n </span>\n )\n },\n },\n ], [currency, t])\n\n if (!suportado) {\n return (\n <Card className=\"py-16 text-center\">\n <Boxes className=\"mx-auto mb-2 h-8 w-8 text-muted-foreground/30\" />\n <p className=\"text-sm text-muted-foreground\">{t('inventory.panel.unsupported')}</p>\n </Card>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <FilterPanel\n title={t('inventory.filters.title')}\n dirty={filtrosPendentes}\n onApply={aplicarFiltros}\n applyLabel={t('inventory.filters.apply')}\n pendingTitle={t('inventory.filters.pending')}\n pendingHint={t('inventory.filters.pendingHint')}\n onClear={filtrosAtivos > 0 ? limparFiltros : undefined}\n clearLabel={t('inventory.filters.clear')}\n busy={loading}\n moreLabel={t('inventory.filters.more')}\n lessLabel={t('inventory.filters.less')}\n advancedCount={(lote.trim() ? 1 : 0) + (validade !== 'all' ? 1 : 0)}\n advanced={\n <>\n <FilterPanelField label={t('inventory.panel.columnBatch')}>\n <Input\n value={lote}\n onChange={(e) => setLote(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') aplicarFiltros() }}\n placeholder={t('inventory.filters.batchPlaceholder')}\n className=\"h-9\"\n />\n </FilterPanelField>\n\n <FilterPanelField label={t('inventory.filters.expiry')}>\n <RequiredFilter\n label={t('inventory.filters.expiry')}\n value={t(`inventory.filters.expiry.${validade}`)}\n icon={CircleDashed}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"space-y-0.5\">\n {EXPIRY_OPTIONS.map((op) => (\n <FilterMenuRow key={op} active={validade === op} onClick={() => { setValidade(op); close() }}>\n {t(`inventory.filters.expiry.${op}`)}\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n </>\n }\n >\n {locations.length > 0 && (\n <FilterPanelField label={t('inventory.filters.location')}>\n <RequiredFilter\n label={t('inventory.filters.location')}\n value={locations.find((l) => l.id === locationId)?.name ?? t('inventory.filters.allLocations')}\n icon={MapPin}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!locationId} onClick={() => { setLocationId(''); close() }}>\n {t('inventory.filters.allLocations')}\n </FilterMenuRow>\n {locations.map((l) => (\n <FilterMenuRow key={l.id} active={locationId === l.id} onClick={() => { setLocationId(l.id); close() }}>\n <span className=\"truncate\">{l.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n\n {categories.length > 0 && (\n <FilterPanelField label={t('inventory.filters.category')}>\n <RequiredFilter\n label={t('inventory.filters.category')}\n value={categories.find((c) => c.id === categoryId)?.name ?? t('inventory.filters.allCategories')}\n icon={Layers}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!categoryId} onClick={() => { setCategoryId(''); close() }}>\n {t('inventory.filters.allCategories')}\n </FilterMenuRow>\n {categories.map((c) => (\n <FilterMenuRow key={c.id} active={categoryId === c.id} onClick={() => { setCategoryId(c.id); close() }}>\n <span className=\"truncate\">{c.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n\n {/* O ESTADO DO ESTOQUE É MULTI-SELEÇÃO, como no V1: «negativo OU abaixo\n do mínimo» é uma pergunta só — a lista do que precisa de compra. */}\n <FilterPanelField label={t('inventory.filters.stockState')} className=\"sm:col-span-2\">\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {HEALTH_ORDER.map((h) => {\n const on = saude.includes(h)\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={h}\n type=\"button\"\n aria-pressed={on}\n onClick={() => setSaude(on ? saude.filter((v) => v !== h) : [...saude, h])}\n className={`font-normal rounded-full border px-2.5 py-1 text-xs transition-colors ${\n on\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-input bg-muted/40 text-muted-foreground hover:bg-muted'\n }`}\n >\n {t(`inventory.filters.health.${h}`)}\n </Button>\n )\n })}\n </div>\n </FilterPanelField>\n </FilterPanel>\n\n {/* A busca do produto mora colada nas linhas, como em toda lista. */}\n <Card className=\"relative px-3 py-1.5\">\n <Search className=\"pointer-events-none absolute left-5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"text\"\n value={produto}\n onChange={(e) => setProduto(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') aplicarFiltros() }}\n placeholder={t('inventory.filters.productPlaceholder')}\n aria-label={t('inventory.filters.productPlaceholder')}\n className=\"h-auto rounded-none border-0 bg-transparent py-1.5 pl-8 pr-3 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n </Card>\n\n <DataTable\n columns={columns}\n data={loading ? [] : rows}\n loading={loading}\n emptyMessage={t('inventory.panel.empty')}\n />\n\n {rows.length > 0 && !loading && (\n <div className=\"flex items-center justify-end gap-6 rounded-lg border bg-muted/30 px-5 py-3 text-sm\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-muted-foreground\">{t('inventory.panel.totalLines')}</span>\n <span className=\"font-semibold tabular-nums\">{totais.linhas}</span>\n </div>\n <div className=\"h-4 w-px bg-border\" />\n <div className=\"flex items-center gap-2\">\n <span className=\"text-muted-foreground\">{t('inventory.panel.totalValue')}</span>\n <span className=\"font-semibold tabular-nums\">{formatCurrency(totais.valor, currency)}</span>\n </div>\n </div>\n )}\n </div>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react'\nimport { CircleDashed, Layers, MapPin } from 'lucide-react'\nimport { CrudListView } from '@fayz-ai/admin'\nimport { DatePicker, FilterMenuRow, FilterPanel, FilterPanelField, RequiredFilter } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { CountSessionStatus, StockCountSession } from '@fayz-ai/inventory/domain/count'\n\nconst COUNT_STATUSES: readonly CountSessionStatus[] = ['open', 'counting', 'closed', 'cancelled']\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 // ── O RECORTE DO V1, na granularidade que uma SESSÃO tem ─────────────────\n //\n // O inventário do V1 recorta por unidade, local, categoria e situação. Uma\n // sessão de contagem carrega local, categoria, situação e a data em que\n // abriu — é o que dá para perguntar aqui, e era exatamente o que faltava:\n // com dezenas de contagens no histórico, «as contagens abertas da Cozinha»\n // só se achava rolando.\n //\n // Tudo do lado do cliente: `getCountSessions` já traz a lista inteira, e um\n // recorte que não vai ao banco aplica na hora — sem rascunho, porque não há\n // consulta para poupar.\n const [locationId, setLocationId] = useState('')\n const [categoryId, setCategoryId] = useState('')\n const [statusFilter, setStatusFilter] = useState<CountSessionStatus[]>([])\n // Periodo pela data de ABERTURA: e a data que a sessao tem desde o primeiro\n // instante. `closedAt` so existe no fim, e recortar por ele esconderia toda\n // contagem em andamento — justamente as que se procura.\n const [dateFrom, setDateFrom] = useState('')\n const [dateTo, setDateTo] = useState('')\n\n const locais = useMemo(() => {\n const vistos = new Map<string, string>()\n for (const s of sessions) {\n if (s.stockLocationId && !vistos.has(s.stockLocationId)) {\n vistos.set(s.stockLocationId, s.stockLocationName ?? s.stockLocationId)\n }\n }\n return [...vistos].map(([id, name]) => ({ id, name })).sort((a, b) => a.name.localeCompare(b.name, 'pt-BR'))\n }, [sessions])\n\n const categorias = useMemo(() => {\n const vistos = new Map<string, string>()\n for (const s of sessions) {\n if (s.categoryId && !vistos.has(s.categoryId)) vistos.set(s.categoryId, s.categoryName ?? s.categoryId)\n }\n return [...vistos].map(([id, name]) => ({ id, name })).sort((a, b) => a.name.localeCompare(b.name, 'pt-BR'))\n }, [sessions])\n\n const filtrosAtivos = (locationId ? 1 : 0) + (categoryId ? 1 : 0) + (statusFilter.length > 0 ? 1 : 0)\n + (dateFrom ? 1 : 0) + (dateTo ? 1 : 0)\n const limparFiltros = () => {\n setLocationId(''); setCategoryId(''); setStatusFilter([]); setDateFrom(''); setDateTo('')\n }\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 .filter((session) => !locationId || session.stockLocationId === locationId)\n .filter((session) => !categoryId || session.categoryId === categoryId)\n .filter((session) => statusFilter.length === 0 || statusFilter.includes(session.status))\n .filter((session) => !dateFrom || (session.openedAt ?? '').slice(0, 10) >= dateFrom)\n .filter((session) => !dateTo || (session.openedAt ?? '').slice(0, 10) <= dateTo)\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, locationId, categoryId, statusFilter, dateFrom, dateTo])\n\n const entity = useMemo(() => buildCountEntity(t), [t])\n\n const filtros = (\n <FilterPanel\n title={t('inventory.filters.title')}\n // Recorte de cliente: não há consulta para poupar, então não há rascunho\n // — o que se escolhe já vale, e a barra de pendência nunca aparece.\n dirty={false}\n onApply={() => {}}\n applyLabel={t('inventory.filters.apply')}\n pendingTitle={t('inventory.filters.pending')}\n onClear={filtrosAtivos > 0 ? limparFiltros : undefined}\n clearLabel={t('inventory.filters.clear')}\n >\n <FilterPanelField label={t('inventory.filters.status')}>\n <RequiredFilter\n label={t('inventory.filters.status')}\n value={\n statusFilter.length === 0\n ? t('inventory.filters.allStatuses')\n : statusFilter.length === 1\n ? t(`inventory.counts.status.${statusFilter[0]}`)\n : t('crud.list.selectedMany', { count: statusFilter.length })\n }\n icon={CircleDashed}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n <div className=\"space-y-0.5\">\n <FilterMenuRow active={statusFilter.length === 0} onClick={() => setStatusFilter([])}>\n {t('inventory.filters.allStatuses')}\n </FilterMenuRow>\n {COUNT_STATUSES.map((st) => {\n const on = statusFilter.includes(st)\n return (\n <FilterMenuRow\n key={st}\n active={on}\n onClick={() => setStatusFilter(on ? statusFilter.filter((v) => v !== st) : [...statusFilter, st])}\n >\n <span className=\"truncate\">{t(`inventory.counts.status.${st}`)}</span>\n </FilterMenuRow>\n )\n })}\n </div>\n </RequiredFilter>\n </FilterPanelField>\n\n {locais.length > 1 && (\n <FilterPanelField label={t('inventory.filters.location')}>\n <RequiredFilter\n label={t('inventory.filters.location')}\n value={locais.find((l) => l.id === locationId)?.name ?? t('inventory.filters.allLocations')}\n icon={MapPin}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!locationId} onClick={() => { setLocationId(''); close() }}>\n {t('inventory.filters.allLocations')}\n </FilterMenuRow>\n {locais.map((l) => (\n <FilterMenuRow key={l.id} active={locationId === l.id} onClick={() => { setLocationId(l.id); close() }}>\n <span className=\"truncate\">{l.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n\n {categorias.length > 1 && (\n <FilterPanelField label={t('inventory.filters.category')}>\n <RequiredFilter\n label={t('inventory.filters.category')}\n value={categorias.find((c) => c.id === categoryId)?.name ?? t('inventory.filters.allCategories')}\n icon={Layers}\n className=\"h-9 w-full justify-start\"\n align=\"start\"\n >\n {(close: () => void) => (\n <div className=\"max-h-72 space-y-0.5 overflow-y-auto\">\n <FilterMenuRow active={!categoryId} onClick={() => { setCategoryId(''); close() }}>\n {t('inventory.filters.allCategories')}\n </FilterMenuRow>\n {categorias.map((c) => (\n <FilterMenuRow key={c.id} active={categoryId === c.id} onClick={() => { setCategoryId(c.id); close() }}>\n <span className=\"truncate\">{c.name}</span>\n </FilterMenuRow>\n ))}\n </div>\n )}\n </RequiredFilter>\n </FilterPanelField>\n )}\n <FilterPanelField label={t('inventory.filters.from')}>\n <DatePicker variant=\"input\" format=\"numeric\" className=\"w-full\" value={dateFrom} onChange={(v) => setDateFrom(v ?? '')} />\n </FilterPanelField>\n <FilterPanelField label={t('inventory.filters.to')}>\n <DatePicker variant=\"input\" format=\"numeric\" className=\"w-full\" value={dateTo} onChange={(v) => setDateTo(v ?? '')} />\n </FilterPanelField>\n </FilterPanel>\n )\n\n return (\n <div className=\"space-y-4\">\n {filtros}\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 </div>\n )\n}\n","import React, { useEffect, useState } from 'react'\nimport { Button, SubpageHeader, Switch, toast, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../context'\nimport type { ProductCategory } from '@fayz-ai/inventory/domain/product'\nimport type { StockLocation } from '@fayz-ai/inventory/domain/stock'\n\nconst FIELD = 'mt-1'\n// Radix Select reserves the empty string for \"nothing chosen\".\nconst ALL_CATEGORIES = '__all__'\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 value={locationId} onValueChange={setLocationId}>\n <SelectTrigger className={FIELD}><SelectValue placeholder={t('inventory.counts.pickLocation')} /></SelectTrigger>\n <SelectContent>\n {locations.map((l) => <SelectItem key={l.id} value={l.id}>{l.name}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n <div>\n <label className=\"text-xs font-medium text-muted-foreground\">{t('inventory.counts.category')}</label>\n <Select value={categoryId || ALL_CATEGORIES} onValueChange={(v) => setCategoryId(v === ALL_CATEGORIES ? '' : v)}>\n <SelectTrigger className={FIELD}><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL_CATEGORIES}>{t('inventory.counts.allCategories')}</SelectItem>\n {categories.map((c) => <SelectItem key={c.id} value={c.id}>{c.name}</SelectItem>)}\n </SelectContent>\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 React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Search } from 'lucide-react'\nimport { Button, Card, ConfirmDialog, FilterPanel, FilterPanelField, SegmentedControl, SubpageHeader, toast, Input } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryConfig, useInventoryProvider, formatCurrency } from '../context'\nimport {\n hidesVariance, isCountFinal, lineVariance, statusAfterEntry, summarizeCount,\n type StockCountItem, type StockCountSession,\n} from '@fayz-ai/inventory/domain/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\n // ── O RECORTE DA CONTAGEM ────────────────────────────────────────────────\n //\n // Uma contagem de deposito tem centenas de linhas, e a pergunta de quem esta\n // com o coletor na mao e sempre a mesma: «o que ainda falta contar?». Sem\n // recorte, a resposta era rolar ate achar a proxima linha em branco.\n //\n // Recorte de CLIENTE — as linhas ja estao todas na tela —, entao nao ha\n // rascunho: escolher ja vale.\n //\n // O QUE O V1 TEM E ESTA TELA NAO PODE TER: curva ABC, validade, giro de 90\n // dias e lote. Nenhum deles existe em `StockCountItem` — inventa-los aqui\n // seria desenhar um filtro que nao filtra.\n const [situacao, setSituacao] = useState<'all' | 'pending' | 'counted' | 'divergent'>('all')\n const [buscaItem, setBuscaItem] = useState('')\n\n const itensVisiveis = useMemo(() => {\n const termo = buscaItem.trim().toLocaleLowerCase('pt-BR')\n return items\n .filter((item) => {\n if (situacao === 'pending') return item.countedQuantity === undefined\n if (situacao === 'counted') return item.countedQuantity !== undefined\n if (situacao === 'divergent') return lineVariance(item) !== 0\n return true\n })\n .filter((item) => !termo\n || (item.productName ?? '').toLocaleLowerCase('pt-BR').includes(termo)\n || (item.productSku ?? '').toLocaleLowerCase('pt-BR').includes(termo))\n }, [items, situacao, buscaItem])\n const closed = isCountFinal(session?.status)\n const hideVariance = hidesVariance(session)\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) setSession({ ...session, status: statusAfterEntry(session.status) })\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 function requestClose() {\n if (summary.uncounted > 0) {\n toast.error(t('inventory.counts.incomplete'), {\n description: t('inventory.counts.incompleteDescription', { count: String(summary.uncounted) }),\n })\n return\n }\n setConfirmingClose(true)\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={requestClose}>\n {t('inventory.counts.close')}\n </Button>\n </div>\n )}\n </div>\n\n {/* O recorte, e a busca colada nas linhas — a mesma anatomia das outras\n telas: o que define o que se ve em cima, a busca encostada no\n resultado. */}\n <FilterPanel\n title={t('inventory.filters.title')}\n dirty={false}\n onApply={() => {}}\n applyLabel={t('inventory.filters.apply')}\n pendingTitle={t('inventory.filters.pending')}\n onClear={situacao !== 'all' ? () => setSituacao('all') : undefined}\n clearLabel={t('inventory.filters.clear')}\n >\n <FilterPanelField label={t('inventory.filters.countState')} className=\"sm:col-span-2\">\n <SegmentedControl\n aria-label={t('inventory.filters.countState')}\n value={situacao}\n onChange={(v) => setSituacao(v as typeof situacao)}\n options={[\n { value: 'all', label: t('inventory.filters.countAll') },\n { value: 'pending', label: t('inventory.filters.countPending') },\n { value: 'counted', label: t('inventory.filters.countDone') },\n { value: 'divergent', label: t('inventory.counts.divergent') },\n ]}\n />\n </FilterPanelField>\n </FilterPanel>\n\n <Card className=\"relative px-3 py-1.5\">\n <Search className=\"pointer-events-none absolute left-5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"text\"\n value={buscaItem}\n onChange={(e) => setBuscaItem(e.target.value)}\n placeholder={t('inventory.filters.itemSearchPlaceholder')}\n aria-label={t('inventory.filters.itemSearchPlaceholder')}\n className=\"h-auto rounded-none border-0 bg-transparent py-1.5 pl-8 pr-3 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n </Card>\n\n <div className=\"rounded-card border bg-card shadow-sm divide-y\">\n {itensVisiveis.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 <div className=\"w-28 shrink-0\">\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=\"h-auto py-2.5 text-right text-base font-medium tabular-nums disabled:opacity-60\"\n />\n </div>\n </div>\n )\n })}\n {itensVisiveis.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', { divergent: String(summary.divergent) })}\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 { 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 { createXlsxReport, type XlsxSheet } from '@fayz-ai/ui'\nimport type { RecipeExportSheet } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { CMV_ALERT_THRESHOLD, CMV_GOOD_THRESHOLD } from '@fayz-ai/inventory/domain/recipe'\n\n// The pricing levers the house's own spreadsheet used (minimum ×2,5, ideal ×3,\n// delivery fee between 23 and 30%). They live once, on the summary tab, and\n// every price in the book is a formula over them — change one and the whole\n// menu reprices.\nconst MIN_MARKUP = 2.5\nconst IDEAL_MARKUP = 3\nconst DELIVERY_FEE = 0.25\nconst NO_CATEGORY = 'Sem categoria'\nconst SUMMARY = 'Resumo'\nconst INPUTS = 'Insumos'\n\nconst quote = (sheet: string) => `'${sheet.replace(/'/g, \"''\")}'`\n\nexport async function exportRecipesXlsx(sheets: RecipeExportSheet[], brand?: string): Promise<void> {\n const report = await createXlsxReport({\n title: 'Fichas Técnicas',\n subtitle: 'Custo, CMV e preço sugerido de cada produto produzido',\n brand,\n landscape: true,\n })\n\n // Codes: the product's SKU when it has a unique one, otherwise a stable\n // sequence. Every line looks its cost up here by code.\n const ingredients = new Map<string, { code: string; name: string; unit?: string; cost: number; usedBy: Set<string> }>()\n const skuSeen = new Map<string, number>()\n for (const s of sheets) for (const g of s.groups) for (const l of g.lines) {\n if (l.ingredientSku) skuSeen.set(l.ingredientSku, (skuSeen.get(l.ingredientSku) ?? 0) + (ingredients.has(l.ingredientId) ? 0 : 1))\n if (!ingredients.has(l.ingredientId)) ingredients.set(l.ingredientId, { code: '', name: l.ingredientName, unit: l.unitAbbr, cost: l.unitCost, usedBy: new Set() })\n ingredients.get(l.ingredientId)!.usedBy.add(s.productId)\n }\n const sorted = [...ingredients.entries()].sort((a, b) => a[1].name.localeCompare(b[1].name))\n sorted.forEach(([id, ing], i) => {\n const sku = sheets.flatMap((s) => s.groups.flatMap((g) => g.lines)).find((l) => l.ingredientId === id)?.ingredientSku\n ing.code = sku && skuSeen.get(sku) === 1 ? sku : `INS-${String(i + 1).padStart(4, '0')}`\n })\n\n // --- Resumo: parameters first, so the formulas below can point at them ----\n const summary = report.sheet(SUMMARY, [\n { header: 'Categoria', width: 20 },\n { header: 'Produto', width: 40 },\n { header: 'Rendimento', width: 12 },\n { header: 'Custo da ficha', type: 'currency', width: 15 },\n { header: 'Preço de venda', type: 'currency', width: 15 },\n { header: 'CMV', type: 'percent', width: 10 },\n { header: 'Preço mínimo', type: 'currency', width: 15 },\n { header: 'Preço ideal', type: 'currency', width: 15 },\n { header: 'Preço delivery', type: 'currency', width: 15 },\n { header: 'Situação', width: 16 },\n ], { tab: 'FF1F2937' })\n summary.section('Parâmetros de preço', 'edite aqui: as abas recalculam')\n const paramRow = summary.facts([\n { label: 'Markup mínimo (×)', value: MIN_MARKUP, type: 'number' },\n { label: 'Markup ideal (×)', value: IDEAL_MARKUP, type: 'number' },\n { label: 'Taxa do delivery', value: DELIVERY_FEE, type: 'percent' },\n ])\n const param = {\n min: `${quote(SUMMARY)}!$A$${paramRow}`,\n ideal: `${quote(SUMMARY)}!$B$${paramRow}`,\n fee: `${quote(SUMMARY)}!$C$${paramRow}`,\n }\n summary.blank()\n\n // --- Insumos: the price list every sheet reads -----------------------------\n const inputs = report.sheet(INPUTS, [\n { header: 'Código', width: 12 },\n { header: 'Insumo', width: 44 },\n { header: 'Unid.', width: 8 },\n { header: 'Custo unitário', type: 'currency', width: 15 },\n { header: 'Usado em (fichas)', type: 'integer', width: 16 },\n ], { subtitle: 'Altere o custo de um insumo e todas as fichas que o usam se recalculam' })\n inputs.table(sorted.map(([, ing]) => [ing.code, ing.name, ing.unit ?? '', ing.cost, ing.usedBy.size]))\n const lookup = (codeCell: string, fallback: number) =>\n `IFERROR(VLOOKUP(${codeCell},${quote(inputs.name)}!$A:$D,4,FALSE),${fallback})`\n\n // --- One tab per category ----------------------------------------------------\n const byCategory = new Map<string, RecipeExportSheet[]>()\n for (const s of sheets) {\n const key = s.categoryName?.trim() || NO_CATEGORY\n byCategory.set(key, [...(byCategory.get(key) ?? []), s])\n }\n const categories = [...byCategory.keys()].sort((a, b) => (a === NO_CATEGORY ? 1 : b === NO_CATEGORY ? -1 : a.localeCompare(b)))\n\n type SummaryLine = { category: string; sheet: RecipeExportSheet; at?: { tab: XlsxSheet; section: number; facts: number } }\n const summaryLines: SummaryLine[] = []\n\n for (const category of categories) {\n const items = byCategory.get(category)!\n const withSheet = items.filter((s) => s.hasSheet)\n if (!withSheet.length) {\n summaryLines.push(...items.map((sheet) => ({ category, sheet })))\n continue\n }\n const tab = report.sheet(category, [\n { header: 'Código', width: 12 },\n { header: 'Insumo', width: 42 },\n { header: 'Unid.', width: 8 },\n { header: 'Quantidade', type: 'quantity', width: 13 },\n { header: 'Custo unitário', type: 'currency', width: 15 },\n { header: 'Custo da linha', type: 'currency', width: 15 },\n { header: '% da ficha', type: 'percent', width: 12 },\n ], { subtitle: `${category} · ${withSheet.length} ${withSheet.length === 1 ? 'ficha' : 'fichas'}` })\n\n for (const sheet of items) {\n if (!sheet.hasSheet) { summaryLines.push({ category, sheet }); continue }\n const aside = [\n sheet.yieldQuantity != null ? `Rende ${sheet.yieldQuantity.toLocaleString('pt-BR')}${sheet.yieldUnitAbbr ? ` ${sheet.yieldUnitAbbr}` : ''}` : '',\n sheet.preparationTimeMinutes ? `${sheet.preparationTimeMinutes} min` : '',\n ].filter(Boolean).join(' · ')\n const section = tab.section(sheet.productName, aside || undefined)\n\n // Facts sit above the lines but read the total below them; the row\n // numbers are known once the lines are laid out, so reserve and fill.\n const linesCount = sheet.groups.reduce((n, g) => n + g.lines.length + (sheet.groups.length > 1 || g.name ? 1 : 0), 0)\n const factsRow = tab.nextRow + 1\n const headerRow = factsRow + 1\n const firstLine = headerRow + 1\n const totalRow = firstLine + linesCount\n const cost = `$F$${totalRow}`\n const price = `$C$${factsRow}`\n // Each formula also carries its value today: previews that never\n // recalculate (Quick Look, Drive, phones) would otherwise show blanks.\n const k = figures(sheet)\n tab.facts([\n { label: 'Custo da ficha', value: { formula: cost, result: k.cost }, type: 'currency' },\n { label: 'Preço mínimo', value: { formula: `${cost}*${param.min}`, result: k.min }, type: 'currency' },\n { label: 'Preço de venda', value: sheet.salePrice || null, type: 'currency' },\n { label: 'CMV', value: { formula: `IF(AND(${price}>0,${cost}>0),${cost}/${price},\"\")`, result: k.cmv }, type: 'percent' },\n { label: 'Preço ideal', value: { formula: `${cost}*${param.ideal}`, result: k.ideal }, type: 'currency' },\n { label: 'Preço delivery', value: { formula: `MAX(${price},${cost}*${param.min}/(1-${param.fee}))`, result: k.delivery }, type: 'currency' },\n { label: 'Markup', value: { formula: `IF(${cost}>0,${price}/${cost},\"\")`, result: k.markup }, type: 'number' },\n ])\n tab.highlight(`D${factsRow}`, cmvRules())\n tab.header(undefined, { pin: false })\n\n let zebra = false\n for (const group of sheet.groups) {\n if (sheet.groups.length > 1 || group.name) {\n tab.row(['', group.name || 'Componentes'], { bold: true, tones: [undefined, 'muted'] })\n }\n for (const line of group.lines) {\n const code = ingredients.get(line.ingredientId)?.code ?? ''\n const r = tab.nextRow\n tab.row([\n code,\n line.ingredientName,\n line.unitAbbr ?? '',\n line.quantity,\n { formula: lookup(`$A${r}`, line.unitCost), result: line.unitCost },\n { formula: `D${r}*E${r}`, result: line.quantity * line.unitCost },\n { formula: `IF(${cost}>0,F${r}/${cost},0)`, result: k.cost > 0 ? (line.quantity * line.unitCost) / k.cost : 0 },\n ], { zebra })\n zebra = !zebra\n }\n }\n tab.row(['', 'Total da ficha', '', '', '', { formula: `SUM(F${firstLine}:F${totalRow - 1})`, result: k.cost }, 1], { total: true })\n tab.blank()\n summaryLines.push({ category, sheet, at: { tab, section, facts: factsRow } })\n }\n }\n\n // --- Resumo table, every figure a link back to the tab ---------------------\n summary.section('Produtos', `${sheets.length} produtos produzidos`)\n const first = summary.nextRow + 1\n summary.table(summaryLines.map(({ category, sheet, at }) => {\n if (!at) {\n return [category, sheet.productName, '', null, sheet.salePrice || null, null, null, null, null, 'Sem ficha']\n }\n const k = figures(sheet)\n const result: Record<string, number | string> = { A: k.cost, B: k.min, C: sheet.salePrice, D: k.cmv, E: k.ideal, F: k.delivery }\n const ref = (col: string) => ({ formula: `${quote(at.tab.name)}!$${col}$${at.facts}`, result: result[col] })\n const yieldText = sheet.yieldQuantity != null ? `${sheet.yieldQuantity.toLocaleString('pt-BR')}${sheet.yieldUnitAbbr ? ` ${sheet.yieldUnitAbbr}` : ''}` : ''\n return [\n category,\n { text: sheet.productName, hyperlink: `#${quote(at.tab.name)}!A${at.section}` },\n yieldText,\n ref('A'), ref('C'), ref('D'), ref('B'), ref('E'), ref('F'),\n sheet.salePrice > 0 ? '' : 'Sem preço',\n ]\n }))\n const last = summary.nextRow - 1\n if (last >= first) summary.highlight(`F${first}:F${last}`, cmvRules())\n\n const day = new Date().toISOString().slice(0, 10)\n await report.download(`fichas-tecnicas-${day}`)\n}\n\n/** Today's values of the block's formulas, with the default parameters. */\nfunction figures(sheet: RecipeExportSheet) {\n const cost = sheet.groups.reduce((sum, g) => sum + g.lines.reduce((s, l) => s + l.quantity * l.unitCost, 0), 0)\n const price = sheet.salePrice\n const min = cost * MIN_MARKUP\n return {\n cost,\n min,\n ideal: cost * IDEAL_MARKUP,\n delivery: Math.max(price, min / (1 - DELIVERY_FEE)),\n // No cost is no CMV, as on screen: 0% would read as a perfect margin.\n cmv: price > 0 && cost > 0 ? cost / price : '',\n markup: cost > 0 ? price / cost : '',\n }\n}\n\nfunction cmvRules() {\n return [\n { when: 'lt' as const, value: CMV_GOOD_THRESHOLD / 100, tone: 'good' as const },\n { when: 'gt' as const, value: CMV_ALERT_THRESHOLD / 100, tone: 'high' as const },\n ]\n}\n","import React, { useCallback, useState } from 'react'\nimport { RecordPickerModal } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryProvider } from '../../context'\nimport type { RecipeCandidate } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { brl } from './shared'\n\n/**\n * \"Nova Ficha Técnica\" creates nothing: it picks the product whose sheet opens.\n * Same picker as a new order — photo, search, price. Only what a sheet makes\n * sense for is offered: sold, intermediate or already produced. A pure\n * ingredient is bought, not produced.\n */\nexport function SelectProductDialog({ onClose, onPick }: {\n onClose: () => void\n onPick: (productId: string) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n const [kind, setKind] = useState<'sale' | 'intermediate' | null>(null)\n\n const search = useCallback(\n (term: string) => provider.searchRecipeCandidates?.(term, kind) ?? Promise.resolve([] as RecipeCandidate[]),\n [provider, kind],\n )\n\n return (\n <RecordPickerModal<RecipeCandidate>\n open\n multiple={false}\n onClose={onClose}\n title={t('inventory.recipes.pickTitle')}\n placeholder={t('inventory.recipes.pickPlaceholder')}\n emptyLabel={t('inventory.recipes.pickEmpty')}\n columns={{ product: t('inventory.sheet.product'), meta: t('inventory.recipes.entity'), value: t('inventory.sheet.salePrice') }}\n search={search}\n rowKey={(p) => p.productId}\n renderRow={(p) => ({\n imageUrl: p.imageUrl,\n title: p.name,\n subtitle: [p.categoryName, t(`inventory.recipes.kind.${p.kind}`)].filter(Boolean).join(' · '),\n meta: p.hasRecipe ? t('inventory.recipes.hasSheet') : t('inventory.recipes.noSheetShort'),\n value: p.salePrice > 0 ? brl(p.salePrice) : '—',\n })}\n onConfirm={(rows) => { if (rows[0]) onPick(rows[0].productId) }}\n filters={{\n options: [\n { id: 'sale', label: t('inventory.recipes.kind.sale') },\n { id: 'intermediate', label: t('inventory.recipes.kind.intermediate') },\n ],\n value: kind,\n onChange: (id) => setKind(id as 'sale' | 'intermediate' | null),\n allLabel: t('inventory.recipes.kind.all'),\n }}\n />\n )\n}\n","import { errorMessage } from '@fayz-ai/core'\nimport React, { useMemo, useRef, useState } from 'react'\nimport { CrudListView, PageActions, useAgentSurface, usePersistedState, useRememberedList, useScrollMemory } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport {\n Button, PageHeaderActions, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, toast,\n} from '@fayz-ai/ui'\nimport { AlertTriangle, Clock, Package, Pencil, Plus, Printer, Utensils } from 'lucide-react'\nimport { useInventoryProvider } from '../context'\nimport type { RecipeListRow } from '@fayz-ai/inventory/domain/recipe-sheet'\nimport { CMV_ALERT_THRESHOLD, CMV_GOOD_THRESHOLD, CMV_TONE, cmvBand, cmvPercent } from '@fayz-ai/inventory/domain/recipe'\nimport { RECIPE_SURFACE_INSTRUCTIONS } from '../lib/agent-tools'\nimport { printRecipe } from './recipe/printRecipe'\nimport { exportRecipesXlsx } from './recipe/exportRecipesXlsx'\nimport { SelectProductDialog } from './recipe/SelectProductDialog'\nimport { brl } from './recipe/shared'\n\n// ---------------------------------------------------------------------------\n// Estoque → Fichas Técnicas, as in V1: every active PRODUCED product, with or\n// without a sheet. A produced product with no sheet is the row this screen\n// exists to surface, so it stays in the list with its badge.\n// ---------------------------------------------------------------------------\n\ntype Row = RecipeListRow & { id: string }\n\nfunction buildEntity(\n t: (key: string, params?: Record<string, string>) => string,\n actions: { onPrint: (r: Row) => void; onEdit: (r: Row) => void },\n): EntityDef {\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 className=\"flex min-w-0 items-center gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg border bg-muted/40\">\n {row.imageUrl\n ? <img src={row.imageUrl} alt=\"\" className=\"h-full w-full object-cover\" loading=\"lazy\" />\n : <Package className=\"h-4 w-4 text-muted-foreground\" />}\n </div>\n <div className=\"min-w-0 max-w-[11rem] xl:max-w-[14rem] 2xl:max-w-[22rem]\">\n <p className=\"truncate font-medium\" title={row.productName}>{row.productName}</p>\n {row.description && <p className=\"truncate text-xs text-muted-foreground\">{row.description}</p>}\n </div>\n </div>\n ),\n },\n {\n key: 'ingredientCount', label: t('inventory.recipes.colIngredients'), type: 'number',\n renderCell: (_v, row: any) => row.recipeId\n ? <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs font-medium tabular-nums\"><Utensils className=\"h-3 w-3\" />{row.ingredientCount}</span>\n : <span className=\"inline-flex rounded-full bg-warning-soft px-2 py-0.5 text-[11px] font-medium text-warning-soft-foreground\">{t('inventory.recipes.noSheet')}</span>,\n },\n {\n key: 'yieldQuantity', label: t('inventory.recipes.colYield'), type: 'text',\n renderCell: (_v, row: any) => <span className=\"text-sm tabular-nums\">{row.recipeId && row.yieldQuantity != null ? `${Number(row.yieldQuantity).toLocaleString('pt-BR')}${row.yieldUnitAbbr ? ` ${row.yieldUnitAbbr}` : ''}` : '—'}</span>,\n },\n {\n key: 'preparationTimeMinutes', label: t('inventory.recipes.colPrep'), type: 'text',\n renderCell: (_v, row: any) => row.preparationTimeMinutes\n ? <span className=\"inline-flex items-center gap-1 text-sm text-muted-foreground\"><Clock className=\"h-3.5 w-3.5\" />{row.preparationTimeMinutes} min</span>\n : <span className=\"text-muted-foreground\">—</span>,\n },\n {\n key: 'cost', label: t('inventory.recipes.colCost'), type: 'currency',\n renderCell: (_v, row: any) => <span className=\"block text-right tabular-nums\">{row.recipeId ? brl(row.cost) : '—'}</span>,\n },\n {\n key: 'salePrice', label: t('inventory.recipes.colSale'), type: 'currency',\n renderCell: (_v, row: any) => <span className=\"block text-right tabular-nums\">{row.salePrice > 0 ? brl(row.salePrice) : '—'}</span>,\n },\n {\n key: 'cmv', label: t('inventory.recipes.colCmv'), type: 'number',\n renderCell: (_v, row: any) => {\n // No cost or no price = no CMV. V1 printed 0,0% for an empty sheet,\n // which reads as a perfect margin (V1-083).\n const cmv = row.cost > 0 ? cmvPercent(row.cost, row.salePrice) : null\n return cmv == null\n ? <span className=\"block text-right text-muted-foreground\">—</span>\n : <span className={`block text-right font-medium tabular-nums ${CMV_TONE[cmvBand(cmv)!]}`}>{cmv.toLocaleString('pt-BR', { minimumFractionDigits: 1, maximumFractionDigits: 1 })}%</span>\n },\n },\n {\n key: 'actions', label: '', type: 'text',\n renderCell: (_v, row: any) => (\n <div className=\"flex justify-end gap-1\" onClick={(e) => e.stopPropagation()}>\n <Tooltip>\n <TooltipTrigger asChild>\n {/* Printing a sheet is a desk job; a phone has no printer to send it to. */}\n <span className=\"hidden md:inline-flex\">\n <Button variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" disabled={!row.recipeId} aria-label={t('inventory.recipes.print')} onClick={() => actions.onPrint(row)}>\n <Printer className=\"h-4 w-4\" />\n </Button>\n </span>\n </TooltipTrigger>\n <TooltipContent>{row.recipeId ? t('inventory.recipes.print') : t('inventory.recipes.printNoSheet')}</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" aria-label={t('inventory.recipes.edit')} onClick={() => actions.onEdit(row)}>\n <Pencil className=\"h-4 w-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('inventory.recipes.edit')}</TooltipContent>\n </Tooltip>\n </div>\n ),\n },\n ],\n }\n}\n\n/** Same rule as the CMV column: no cost means no CMV, not a perfect margin. */\nfunction rowCmvBand(r: Row) {\n return cmvBand(r.cost > 0 ? cmvPercent(r.cost, r.salePrice) : null) ?? 'none'\n}\n\nexport function RecipesView({ onOpenProduct }: {\n /** Opens the product on its Ficha Técnica tab. */\n onOpenProduct: (productId: string) => void\n}) {\n const t = useTranslation()\n const provider = useInventoryProvider()\n\n // Back from a product lands on the same rows, filters and position; a save\n // made there re-reads just that row.\n const { rows, error: loadError, reload: load } = useRememberedList<Row>({\n key: 'inventory.recipes',\n load: async () => (await provider.getRecipeList!()).map((r) => ({ ...r, id: r.productId })),\n loadOne: provider.getRecipeListRow\n ? async (id) => { const r = await provider.getRecipeListRow!(id); return r ? { ...r, id: r.productId } : null }\n : undefined,\n // Sheet saves announce their product, so the recipes table itself is not listened to.\n tables: ['products', 'categories', 'plg_inventory_product_details'],\n rowFor: (list, id) => list.find((r) => r.productId === id || r.recipeId === id),\n })\n const [search, setSearch] = usePersistedState('inventory.recipes.search', '')\n const [filters, setFilters] = usePersistedState<Record<string, string | undefined>>('inventory.recipes.filters', {})\n const [collapsedGroups, setCollapsedGroups] = usePersistedState<string[]>('inventory.recipes.collapsed', [])\n const scrollAnchor = useScrollMemory('inventory.recipes')\n const [picking, setPicking] = useState(false)\n\n const visible = useMemo(() => {\n const term = search.trim().toLowerCase()\n if (!rows) return null\n const { kind, category, cmv } = filters\n return rows.filter((r) => {\n if (term && !r.productName.toLowerCase().includes(term) && !(r.description ?? '').toLowerCase().includes(term)) return false\n if (kind === 'sale' && !r.isForSale) return false\n if (kind === 'intermediate' && !r.isIntermediate) return false\n if (category !== undefined && (r.categoryName ?? '') !== category) return false\n if (cmv && rowCmvBand(r) !== cmv) return false\n return true\n })\n }, [rows, search, filters])\n\n const facets = useMemo(() => {\n const categories = [...new Set((rows ?? []).map((r) => r.categoryName ?? ''))]\n .sort((a, b) => (a === '' ? 1 : b === '' ? -1 : a.localeCompare(b)))\n return [\n {\n field: 'kind', label: t('inventory.recipes.filterKind'), allLabel: t('inventory.recipes.filterKindAll'),\n options: [\n { value: 'sale', label: t('inventory.recipes.kindSale') },\n { value: 'intermediate', label: t('inventory.recipes.kindIntermediate') },\n ],\n },\n {\n field: 'category', label: t('inventory.recipes.filterCategory'), allLabel: t('inventory.recipes.filterCategoryAll'),\n options: categories.map((c) => ({ value: c, label: c || t('inventory.recipes.noCategory') })),\n },\n {\n field: 'cmv', label: t('inventory.recipes.filterCmv'), allLabel: t('inventory.recipes.filterCmvAll'),\n options: [\n { value: 'good', label: t('inventory.recipes.cmvGood', { pct: String(CMV_GOOD_THRESHOLD) }) },\n { value: 'attention', label: t('inventory.recipes.cmvAttention', { from: String(CMV_GOOD_THRESHOLD), to: String(CMV_ALERT_THRESHOLD) }) },\n { value: 'high', label: t('inventory.recipes.cmvHigh', { pct: String(CMV_ALERT_THRESHOLD) }) },\n { value: 'none', label: t('inventory.recipes.cmvNone') },\n ],\n },\n ]\n }, [rows, t])\n\n const exportAll = async () => {\n const id = toast.loading(t('inventory.recipes.exporting'))\n try {\n await exportRecipesXlsx(await provider.getRecipeExport!())\n toast.success(t('inventory.recipes.exported'), { id })\n } catch (e) {\n toast.error(errorMessage(e), { id })\n }\n }\n\n const entity = useMemo(() => buildEntity(t, {\n onPrint: (r) => { printRecipe(provider, r).catch((e) => toast.error(errorMessage(e))) },\n onEdit: (r) => onOpenProduct(r.productId),\n }), [t, provider, onOpenProduct])\n\n const groupBy = useMemo(() => ({\n getKey: (r: { id: string }) => (r as Row).categoryName,\n emptyLabel: t('inventory.recipes.noCategory'),\n collapsed: collapsedGroups,\n onCollapsedChange: setCollapsedGroups,\n }), [t, collapsedGroups, setCollapsedGroups])\n\n // The model needs real ids and real costs, not a guess at the catalogue.\n const surfaceRows = useRef<Row[]>([])\n surfaceRows.current = rows ?? []\n const surface = useMemo(() => ({\n id: 'inventory.recipes',\n pluginId: 'inventory',\n role: 'finance' as const,\n instructions: RECIPE_SURFACE_INSTRUCTIONS,\n describe: () => ({\n title: 'Fichas técnicas',\n state: {\n producedWithoutRecipe: surfaceRows.current.filter((r) => !r.recipeId).map((r) => ({ productId: r.productId, name: r.productName })),\n recipes: surfaceRows.current.filter((r) => r.recipeId).map((r) => ({\n id: r.recipeId, productId: r.productId, product: r.productName, cost: r.cost,\n cmv: r.cost > 0 ? cmvPercent(r.cost, r.salePrice) : null,\n })),\n cmvAlertThreshold: CMV_ALERT_THRESHOLD,\n },\n }),\n tools: [],\n }), [])\n useAgentSurface(surface)\n\n if (loadError) {\n return (\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 variant=\"outline\" className=\"mt-4\" onClick={() => void load()}>{t('inventory.recipes.retry')}</Button>\n </div>\n )\n }\n\n return (\n <TooltipProvider delayDuration={300}>\n <div ref={scrollAnchor as React.RefObject<HTMLDivElement>} />\n <PageHeaderActions>\n <PageActions\n actions={[{\n id: 'new-recipe',\n label: t('inventory.recipes.newRecipe'),\n icon: Plus,\n intent: 'primary',\n creates: true,\n permission: { feature: 'inventory', action: 'edit' },\n onSelect: () => setPicking(true),\n }]}\n />\n </PageHeaderActions>\n <CrudListView\n entityDef={entity}\n items={visible as unknown as Array<{ id: string }> | null}\n total={visible?.length ?? 0}\n search={search}\n onSearchChange={setSearch}\n searchPlaceholder={t('inventory.recipes.searchPlaceholder')}\n facets={facets}\n activeFilters={filters}\n onFacetChange={(field, value) => setFilters((prev) => ({ ...prev, [field]: value }))}\n onRowClick={(row) => onOpenProduct((row as unknown as Row).productId)}\n emptyMessage={t('inventory.recipes.noRecipes')}\n onRefresh={() => load()}\n onExport={provider.getRecipeExport ? () => { void exportAll() } : undefined}\n feature=\"inventory\"\n groupBy={groupBy}\n />\n {picking && (\n <SelectProductDialog\n onClose={() => setPicking(false)}\n onPick={(productId) => { setPicking(false); onOpenProduct(productId) }}\n />\n )}\n </TooltipProvider>\n )\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { CalendarRange, Check, ClipboardCheck, ListFilter, PackageCheck } from 'lucide-react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport {\n ListView, Button, Badge, toast, DraftCommitBar,\n Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, Textarea, Input,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useInventoryStore, useInventoryConfig, formatCurrency } from '../context'\nimport { summarizeCount, type StockCountItem } from '@fayz-ai/inventory/domain/count'\nimport { usageLineKey, type UsageAuditCorrection, type UsageAuditEntry } from '@fayz-ai/inventory/domain/usage-audit'\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\n/** As três leituras da mesma fila — o que a barra de modos oferece. */\ntype AuditQueue = 'pending' | 'divergent' | 'all'\n\nconst keyOf = usageLineKey\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\n/**\n * O DIA É O DIA, não o fuso.\n *\n * O consumo clínico é gravado com a DATA da execução (`executed_on`), sem\n * hora. A vista a promove a instante em UTC, e mostrá-lo no fuso de quem olha\n * empurrava tudo três horas para trás: o que o injetor lançou hoje aparecia\n * como \"ontem, 21:00\". Quando a linha tem data própria, é ela que manda — sem\n * hora, porque hora ali seria inventada.\n */\nfunction formatUsedAt(iso: string, locale: string, dia?: string | null): string {\n if (dia && /^\\d{4}-\\d{2}-\\d{2}$/.test(dia)) {\n const [a, m, d] = dia.split('-')\n return new Date(Number(a), Number(m) - 1, Number(d))\n .toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: '2-digit' })\n }\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 <div className=\"w-24 shrink-0\">\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={`h-auto py-2.5 text-right font-medium tabular-nums ${invalid ? 'border-destructive' : ''}`}\n />\n </div>\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=\"mt-1 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 const approveUsageBatch = useInventoryStore((s) => s.approveUsageBatch)\n const patchUsageAuditEntries = useInventoryStore((s) => s.patchUsageAuditEntries)\n\n const [search, setSearch] = useState('')\n // A tela abre na DIVERGÊNCIA, e isso é o V1, não uma otimização disfarçada:\n // a `Auditoria de Uso` de lá é uma FILA de conferência, e o que entra nela é\n // a linha cujo usado difere do padrão da ficha. Abrir em \"tudo\" é oferecer\n // 116.911 consumos ordenados por data para mostrar os 50 primeiros — uma\n // pergunta que ninguém faz e que a vista não consegue responder com índice,\n // porque a ordenação atravessa um UNION ALL e obriga a materializar os dois\n // ramos. Medido no Espaço Facial: \"tudo\" custa 2,8 s no banco e estoura os\n // 8 s do PostgREST; a fila de divergências custa 0,53 s e traz as 172 linhas\n // que alguém de fato precisa conferir.\n //\n // \"Tudo\" continua a um clique de distância, na aba ao lado.\n // O PADRÃO É \"PENDENTES\", que é o que o V1 abre: *\"Revise e aprove os\n // produtos utilizados nos atendimentos\"*, com o contador de pendentes no\n // canto. Abrir em \"fora do padrão\" escondia justamente o que o injetor\n // acabou de lançar — um consumo igual ao da ficha técnica tem variação zero\n // e nunca aparecia ali.\n const [queue, setQueue] = useState<AuditQueue>('pending')\n const [drafts, setDrafts] = useState<Record<string, string>>({})\n const [confirming, setConfirming] = useState(false)\n const [saving, setSaving] = useState(false)\n // O estado inicial da loja é lista vazia com `carregando` FALSO, então entre\n // a primeira pintura e a primeira resposta a tela dizia \"Nenhum consumo fora\n // do padrão\" — a mesma frase que ela usa para \"conferi e está tudo certo\".\n // Duas coisas diferentes com a mesma cara: quem abriu a tela concluía que não\n // havia nada a conferir quando havia 17.\n const [loadedOnce, setLoadedOnce] = useState(false)\n // A FILA TEM UM PERÍODO, e o padrão é curto de propósito.\n //\n // A vista atravessa a história inteira do consumo — 116.939 linhas neste\n // tenant — e ordenar tudo por data estourou o tempo do PostgREST mesmo já\n // filtrando por divergência: o banco leva 1,4 s sozinho e a requisição da\n // tela voltava `canceling statement due to statement timeout`. Com uma\n // janela de 30 dias o mesmo pedido custa 0,65 s.\n //\n // Não é só desempenho: a fila do V1 é o que CHEGOU para conferir, não o\n // arquivo. O período fica à vista e \"Tudo\" continua a um clique.\n const [dias, setDias] = useState<number | null>(30)\n // Falhar não é estar vazio. Com o erro engolido num toast que some, a tela\n // ficava dizendo \"Nenhum consumo fora do padrão\" sobre uma consulta que\n // nunca respondeu — a frase de quem conferiu tudo, na tela de quem não viu\n // nada.\n const [erro, setErro] = useState<string | null>(null)\n\n const desde = useMemo(() => {\n if (dias == null) return undefined\n const d = new Date()\n d.setDate(d.getDate() - dias)\n return d.toISOString()\n }, [dias])\n\n useEffect(() => {\n let active = true\n setErro(null)\n fetchUsageAudit({\n search: search || undefined,\n divergentOnly: queue === 'divergent',\n pendingOnly: queue === 'pending',\n from: desde,\n })\n .catch((err: any) => {\n if (active) setErro(err?.message ?? String(err))\n toast.error(t('inventory.usageAudit.loadFailed'), { description: err?.message })\n })\n .finally(() => { if (active) setLoadedOnce(true) })\n return () => { active = false }\n }, [search, queue, desde])\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 // Quais linhas ESTA sessão acabou de conferir, e como.\n //\n // O banco guarda `is_corrected`, que quer dizer \"alguém já olhou\" — e é a\n // mesma marca de uma correção de quantidade. Para o rótulo do selo eu preciso\n // do verbo que ACABOU de ser usado (baixou ou só aprovou), e isso a linha\n // recarregada não distingue. Vive na tela porque é da tela: some na próxima\n // carga, quando a linha sai da fila por mérito próprio.\n const [conferidas, setConferidas] = useState<Record<string, 'posted' | 'approved'>>({})\n // As linhas em voo — uma aprovação solta ou um lote inteiro.\n const [aprovando, setAprovando] = useState<Set<string>>(new Set())\n\n /**\n * Aprovar N linhas de uma vez — uma da fileira de botões, ou as marcadas.\n *\n * NÃO RECARREGA A FILA. Conferir é descer a lista clicando, e recarregar a\n * cada clique jogava a tabela fora: a rolagem voltava ao topo e a linha\n * seguinte — justamente onde a pessoa ia clicar — mudava de lugar. O servidor\n * já respondeu o que aconteceu; a tela escreve isso nas linhas atingidas\n * (`patchUsageAuditEntries`) e fica parada.\n */\n const aprovarLinhas = useCallback(async (alvos: UsageAuditEntry[], baixar: boolean) => {\n if (!alvos.length) return\n const chaves = alvos.map(keyOf)\n setAprovando((prev) => new Set([...prev, ...chaves]))\n try {\n const lines = alvos.map((e) => ({ itemId: e.itemId, productId: e.productId }))\n const r = await approveUsageBatch({ post: baixar, lines })\n\n // SEM SALDO NÃO É SUCESSO. A linha continua na fila, e a mensagem diz o\n // produto e o número — \"dê entrada ou aprove sem baixar\" é a decisão de\n // quem está no estoque, não do sistema.\n const semSaldo = r.linesNoStock ?? 0\n const passaram = baixar ? r.linesPosted : r.linesApproved\n if (baixar && r.linesPosted === 0 && semSaldo > 0) {\n const f = r.missing?.[0]\n toast.warning(t('inventory.usageAudit.noStock'), {\n description: f ? `${f.product} — precisa ${f.needed}, há ${f.available}` : undefined,\n })\n return\n }\n toast.success(baixar\n ? t('inventory.usageAudit.posted', { count: String(r.linesPosted) })\n : t('inventory.usageAudit.approved', { count: String(r.linesApproved) }), {\n // Um lote parcial precisa dizer quantas ficaram para trás, ou some a\n // diferença entre \"aprovei 12\" e \"pedi 15\".\n description: semSaldo > 0\n ? t('inventory.usageAudit.batchNoStock', { count: String(semSaldo) })\n : undefined,\n })\n\n // MARCA SÓ O QUE PASSOU. Num lote parcial o servidor diz quantas linhas\n // venceram, não QUAIS — então só posso escrever o selo quando todas\n // passaram. Com sobra, a fila se recarrega e cada linha volta com a\n // verdade do banco, que é melhor que a tela adivinhar qual foi.\n if (semSaldo > 0 || passaram !== alvos.length) {\n await fetchUsageAudit({\n search: search || undefined,\n divergentOnly: queue === 'divergent',\n pendingOnly: queue === 'pending',\n from: desde,\n })\n return\n }\n patchUsageAuditEntries(lines, { isCorrected: true, ...(baixar ? { stockPosted: true } : {}) })\n setConferidas((prev) => {\n const next = { ...prev }\n for (const k of chaves) next[k] = baixar ? 'posted' : 'approved'\n return next\n })\n } catch (err: any) {\n toast.error(t('inventory.usageAudit.approveFailed'), { description: err?.message })\n } finally {\n setAprovando((prev) => {\n const next = new Set(prev)\n for (const k of chaves) next.delete(k)\n return next\n })\n }\n }, [approveUsageBatch, patchUsageAuditEntries, fetchUsageAudit, search, queue, desde, t])\n\n // As três leituras que a célula faz sem entrar na lista de dependências das\n // colunas. Ver o comentário no fim de `columns`.\n const conferidasRef = useRef(conferidas)\n conferidasRef.current = conferidas\n const aprovandoRef = useRef(aprovando)\n aprovandoRef.current = aprovando\n const aprovarLinhasRef = useRef(aprovarLinhas)\n aprovarLinhasRef.current = aprovarLinhas\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 /* NOME LONGO NÃO EMPURRA A TABELA. \"Ao Redor da Boca e Código de\n Barras - Ultraformer\" alargava a coluna e espremia quantidade,\n profissional e as ações para fora da tela. Aqui o nome tem teto e\n corta com reticências — o inteiro fica no `title`, a um passar de\n mouse, e a linha continua legível no celular. */\n <div className=\"min-w-[10rem] max-w-[18rem]\">\n <div className=\"truncate font-medium\" title={entry.productName ?? undefined}>\n {entry.productName ?? t('inventory.usageAudit.unnamedProduct')}\n </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=\"truncate text-xs text-muted-foreground\" title={entry.itemName}>{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 {/* O selo diz o VERBO quando ele acabou de ser usado nesta tela —\n \"Baixado\" e \"Aprovado\" não são a mesma coisa, e o banco guarda\n as duas sob a mesma marca de \"alguém já olhou\". Linha que já\n chegou conferida continua dizendo \"Corrigido\", que é o que ela\n é sem que a tela precise inventar o resto. */}\n {(entry.isCorrected || conferidasRef.current[keyOf(entry)]) && (\n <Badge\n variant={conferidasRef.current[keyOf(entry)] ? 'success' : 'outline'}\n className=\"ml-2 text-[10px]\"\n >\n {conferidasRef.current[keyOf(entry)] === 'posted'\n ? t('inventory.usageAudit.badgePosted')\n : conferidasRef.current[keyOf(entry)] === 'approved'\n ? t('inventory.usageAudit.badgeApproved')\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, (row.original as UsageAuditEntry).movementDate)}\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=\"block max-w-[10rem] truncate text-xs\" title={entry.performedByName ?? undefined}>\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=\"block max-w-[12rem] truncate text-xs text-muted-foreground\" title={entry.customerName ?? undefined}>\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 {\n // AS DUAS AÇÕES DO V1, na linha, com os verbos dele.\n //\n // \"Baixar no estoque\" aceita E desconta; \"Aprovar\" aceita e não mexe no\n // saldo — é o consumo que não sai da prateleira da casa (produto do\n // próprio cliente, amostra, item já baixado por fora). Separá-las é o\n // que impede que conferir vire baixa automática.\n id: 'acoes', header: () => <span className=\"block text-right\">{t('inventory.usageAudit.columnActions')}</span>,\n cell: ({ row }: any) => {\n const entry = row.original as UsageAuditEntry\n const key = keyOf(entry)\n // Conferida é conferida: oferecer de novo os dois verbos convida a\n // aprovar duas vezes a mesma linha.\n const feito = !!conferidasRef.current[key]\n const ocupado = aprovandoRef.current.has(key)\n if (feito) return <span className=\"block text-right text-xs text-muted-foreground\">—</span>\n return (\n <div className=\"flex items-center justify-end gap-1\">\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n disabled={ocupado}\n onClick={() => void aprovarLinhasRef.current([entry], true)}\n title={t('inventory.usageAudit.postHint')}\n className=\"disabled:pointer-events-auto rounded-button bg-foreground px-2 py-1 text-[11px] font-semibold text-background disabled:opacity-40\"\n >\n {t('inventory.usageAudit.post')}\n </Button>\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n disabled={ocupado}\n onClick={() => void aprovarLinhasRef.current([entry], false)}\n title={t('inventory.usageAudit.approveHint')}\n className=\"disabled:pointer-events-auto rounded-button border border-input px-2 py-1 text-[11px] font-medium hover:bg-muted disabled:opacity-40\"\n >\n {t('inventory.usageAudit.approve')}\n </Button>\n </div>\n )\n },\n },\n // As colunas NÃO dependem de `conferidas` nem de `aprovando`: refazê-las\n // remonta a célula do campo aberto e leva o foco junto — o mesmo motivo que\n // já obrigava `draftsRef`. As duas leituras voláteis vão por ref, e quem\n // repinta a linha é o `usageAudit` do store, que a aprovação acabou de\n // mudar.\n ], [currency, locale, t, setDraft, focusNext, registerRef])\n\n const costDelta = summary.varianceValue\n\n return (\n <div className=\"space-y-3\">\n {/* UM DESENHO DE FILTRO SÓ.\n A fila (Pendentes · Divergentes · Todos) era uma banda de abas por\n cima da tabela, e o período uma pastilha dentro dela: dois controles\n que reduzem a MESMA lista, em duas alturas diferentes, com dois\n desenhos. Os dois viraram pastilha na linha da busca. \"Todos\" é a\n pastilha limpa — é o que `allLabel` já significa em toda a casa. */}\n {erro && (\n <p className=\"rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive\">\n {t('inventory.usageAudit.loadFailed')} — {erro}\n </p>\n )}\n\n {/* O período viaja na MESMA linha da busca, como toda pastilha de filtro\n da casa: recortar e buscar reduzem a mesma lista. A fileira de botões\n que ele era antes gastava uma linha acima da tabela para mostrar o\n tempo todo duas opções que não estavam valendo. */}\n <ListView<UsageAuditEntry>\n columns={columns}\n data={entries}\n loading={loading || !loadedOnce}\n total={total}\n getRowId={(row) => keyOf(row)}\n // CONFERIR EM LOTE — os MESMOS dois verbos da linha, sobre o que\n // estiver marcado. Descer 172 linhas clicando duas vezes em cada uma é\n // a fila do Espaço Facial inteira num dia; marcar o bloco que já foi\n // olhado e aprovar de uma vez é o gesto que a contagem sempre teve e\n // esta tela não.\n //\n // Linha já conferida sai do lote em silêncio: o servidor a recusaria,\n // e um \"aprovei 12 de 15\" sem dizer por quê é pior que não oferecê-la.\n bulkActions={[\n {\n id: 'post',\n label: t('inventory.usageAudit.post'),\n icon: PackageCheck,\n onSelect: (rows) => aprovarLinhas(rows.filter((r) => !conferidas[keyOf(r)]), true),\n },\n {\n id: 'approve',\n label: t('inventory.usageAudit.approve'),\n icon: Check,\n onSelect: (rows) => aprovarLinhas(rows.filter((r) => !conferidas[keyOf(r)]), false),\n },\n ]}\n searchPlaceholder={t('inventory.usageAudit.searchPlaceholder')}\n search={search}\n onSearchChange={setSearch}\n searchDebounce={300}\n filterDefs={[\n {\n id: 'queue',\n label: t('inventory.usageAudit.filterLabel'),\n icon: ListFilter,\n allLabel: t('inventory.usageAudit.filterAll'),\n options: [\n { value: 'pending', label: t('inventory.usageAudit.filterPending') },\n { value: 'divergent', label: t('inventory.usageAudit.filterDivergent') },\n ],\n value: queue === 'all' ? undefined : queue,\n onChange: (v) => setQueue((v as AuditQueue) ?? 'all'),\n },\n {\n id: 'period',\n label: t('inventory.usageAudit.periodLabel'),\n icon: CalendarRange,\n allLabel: t('inventory.usageAudit.periodAll'),\n options: [\n { value: '30', label: t('inventory.usageAudit.period30') },\n { value: '90', label: t('inventory.usageAudit.period90') },\n ],\n value: dias == null ? undefined : String(dias),\n onChange: (v) => setDias(v ? Number(v) : null),\n },\n ]}\n filtersLabel={t('inventory.usageAudit.filtersLabel')}\n onClearFilters={() => { setQueue('all'); setDias(null) }}\n emptyMessage={erro\n ? t('inventory.usageAudit.loadFailed')\n : queue === 'divergent'\n ? t('inventory.usageAudit.emptyDivergent')\n : queue === 'pending'\n ? t('inventory.usageAudit.emptyPending')\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","// ---------------------------------------------------------------------------\n// O que o Estoque do V1 tem e este ainda não.\n// ---------------------------------------------------------------------------\n// Lido do menu do V1 da Artorius (captura de 30/09/2026) e medido no banco de\n// produção. Os números são de lá: quantas linhas existem, e quantas são da\n// Artorius. Um «em breve» sem tamanho não ajuda a priorizar.\n//\n// A Produção fica DE FORA por decisão do founder — são seis telas (Visão Geral,\n// Planejamento, Ordens, Execução, Lotes & Rastreabilidade, Custos & Rendimentos)\n// e um assunto próprio, não um buraco do estoque.\n// ---------------------------------------------------------------------------\nimport React from 'react'\nimport { ComingSoon } from '@fayz-ai/ui'\n\n/** Transferência entre locais de estoque. */\nexport function TransfersView() {\n return (\n <ComingSoon\n title=\"Transferências\"\n summary=\"Mover saldo de um local de estoque para outro — da câmara fria para o salão, do depósito para a cozinha — sem que isso vire entrada nem saída.\"\n v1Path=\"Estoque → Transferências\"\n measured=\"7 transferências no V1 inteiro, nenhuma da Artorius. Eles têm 5 locais de estoque e movimentam tudo por entrada de nota.\"\n missing={[\n 'A transferência é DOIS movimentos ligados, não um: sai de um local e entra no outro pelo mesmo custo',\n 'O movimento de estoque do V2 já tem `destination_location_id` — falta a tela e a regra de aprovação',\n 'O V1 tem aprovador de transferência (stock_transfer_approvers); decidir se isso vem junto',\n ]}\n />\n )\n}\n\n/** Requisição interna — a cozinha pede ao depósito. */\nexport function RequisitionsView() {\n return (\n <ComingSoon\n title=\"Requisições\"\n summary=\"O pedido interno: a cozinha requisita do depósito, alguém separa, e a baixa acontece quando sai — não quando foi pedido.\"\n v1Path=\"Estoque → Requisições\"\n measured=\"ZERO requisições no V1 inteiro, em nenhum cliente. A tela existe lá e nunca foi usada.\"\n missing={[\n 'Antes de construir: confirmar que alguém quer. Nenhum cliente do V1 usou isto em nenhum momento',\n 'O V1 tem sete tabelas para o assunto (requisição, item, lote, modelo, evento, ajuste, idempotência) e nenhuma linha',\n 'Se vier, é fluxo de pedido→separação→baixa, com o saldo reservado no meio',\n ]}\n />\n )\n}\n\n/** Locais de estoque — cadastro que a Artorius USA. */\nexport function StockLocationsView() {\n return (\n <ComingSoon\n title=\"Locais de Estoque\"\n summary=\"Onde a mercadoria fica: depósito, câmara congelada, salão. Cada movimento acontece em um local, e o saldo é por local.\"\n v1Path=\"Estoque → Locais de Estoque\"\n measured=\"A Artorius tem 5 locais no V1 e 6 já migrados para cá (Estoque principal, CÂMARA CONGELADA…). O dado atravessou; falta a tela para mexer nele.\"\n missing={[\n 'A tabela `plg_inventory_stock_locations` já existe e já recebeu os locais — é CRUD, não porte de regra',\n 'A conciliação de nota já escolhe o local; hoje quem cria um novo tem de pedir a alguém',\n 'Ligar local à unidade, que é o que a RLS usa para decidir quem vê qual saldo',\n ]}\n />\n )\n}\n\n/** Controle de temperatura — HACCP de cozinha. */\nexport function TemperatureView() {\n return (\n <ComingSoon\n title=\"Controle de Temperatura\"\n summary=\"O registro de temperatura dos equipamentos — câmara, freezer, balcão — com a leitura de cada turno e o alerta quando sai da faixa.\"\n v1Path=\"Estoque → Controle de Temperatura\"\n measured=\"70 pontos de controle e 138 leituras no V1, nenhum da Artorius. É a vigilância sanitária de quem já foi cobrado por ela.\"\n missing={[\n 'Cadastrar o ponto de controle (equipamento, faixa aceitável, quantas leituras por dia)',\n 'A leitura do turno, com quem leu e quando — é prova para a fiscalização',\n 'O alerta quando sai da faixa; sem isso o registro vira papel passado',\n ]}\n />\n )\n}\n\n/** Indicadores de estoque. */\nexport function StockIndicatorsView() {\n return (\n <ComingSoon\n title=\"Indicadores\"\n summary=\"Ponto de pedido, estoque mínimo e máximo por produto e por local — e o que está abaixo do mínimo agora.\"\n v1Path=\"Estoque → Indicadores\"\n measured=\"Nenhum parâmetro cadastrado no V1, em nenhum cliente (`stock_center_product_params` está vazia). A Artorius compra por hábito, não por ponto de pedido.\"\n missing={[\n 'O parâmetro por produto × local: mínimo, máximo, ponto de pedido',\n 'A lista do que está abaixo do mínimo — o painel do Estoque já mostra «estoque baixo», mas com limiar chutado',\n 'Sugestão de compra a partir disso é o passo seguinte, e é o que liga o estoque à Entrada de Notas',\n ]}\n />\n )\n}\n\n/** Alteração em massa de produtos — sub-item de Produtos no V1. */\nexport function BulkProductEditView() {\n return (\n <ComingSoon\n title=\"Alteração em massa\"\n summary=\"Mudar preço, custo, categoria ou unidade de muitos produtos de uma vez, sem abrir um por um.\"\n v1Path=\"Estoque → Produtos → Alteração em massa\"\n measured=\"A Tati editou 184 produtos no V1 em quatro dias. Um por um.\"\n missing={[\n 'Selecionar por filtro (categoria, tipo, fornecedor) e aplicar a mudança ao conjunto',\n 'Pré-visualizar o que vai mudar ANTES de gravar — alteração em massa errada é difícil de desfazer',\n 'Registrar quem mudou o quê: é a diferença entre correção e acidente',\n ]}\n />\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 variant=\"bare\" size=\"bare\" onClick={() => void complete()} disabled={preparing} className=\"font-normal 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, { useMemo } from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ModulePage, PageTransition, ComingSoon, type ModuleNavItem } from '@fayz-ai/ui'\nimport { InventoryContextProvider, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { InventoryUIState } from '@fayz-ai/inventory/store'\nimport type { PluginRegistryDef, PluginQuickAction } from '@fayz-ai/core'\nimport { useModuleNavigation, ModuleActionBar, createViewRouter, PluginSettingsPanel, RegistryCrudView, useTenantPluginSettings, usePluginOnboardingGate, PluginOnboardingGateSkeleton } 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 { StockPanelView } from './StockPanelView'\nimport { StockCountsView } from './StockCountsView'\nimport { StockCountFormView } from './StockCountFormView'\nimport { StockCountSessionView } from './StockCountSessionView'\nimport { RecipesView } from './RecipesView'\nimport { UsageAuditView } from './UsageAuditView'\nimport {\n StockLocationsView, TemperatureView, BulkProductEditView,\n StockIndicatorsView, TransfersView, RequisitionsView,\n} from './GapScreens'\nimport { InventoryGeneralSettings, INVENTORY_MODULE_DEFAULTS, useInventoryHouseModules } from '../components/InventoryGeneralSettings'\nimport { InventoryOnboarding } from '../components/InventoryOnboarding'\n\ntype HouseModules = Pick<typeof INVENTORY_MODULE_DEFAULTS, 'requisitions' | 'usageAudit' | 'temperature' | 'hiddenViews'>\n\nfunction buildNav(config: ResolvedInventoryConfig, view: string, navigate: (v: string) => void, t: (key: string) => string, house: HouseModules): ModuleNavItem[] {\n const items: ModuleNavItem[] = [\n // Tudo o que se faz COM o catálogo mora aqui: a lista, como ela se agrupa\n // (Categorias) e como se mexe em muitos de uma vez. A primeira filha\n // chama-se «Produtos» e não «Lista» porque o nome de uma tela é o que ela\n // mostra, e «Lista» só diz o formato.\n // O Resumo abre o módulo: é a única tela daqui que responde sem que se peça\n // nada — quanto vale o estoque, quantos itens, o que está abaixo do mínimo.\n { id: 'dashboard', label: t('inventory.nav.dashboard'), icon: 'BarChart3', active: view === 'dashboard', onClick: () => navigate('dashboard') },\n // Depois dele, o catálogo: a lista, como ela se agrupa (Categorias) e como\n // se mexe em muitos de uma vez.\n ...(config.modules.products ? [{\n id: 'products', label: t('inventory.nav.products'), icon: 'Package',\n active: view.startsWith('products') || view === 'product-categories' || view === 'bulk-products',\n children: [\n { id: 'products-new', kind: 'action' as const, label: t('inventory.nav.new'), active: view === 'products-new', onClick: () => navigate('products-new') },\n { id: 'products-list', label: t('inventory.nav.products'), defaultChild: true, active: view === 'products-list' || view.startsWith('products-') && view.includes(':') && !view.startsWith('products-recipe:'), onClick: () => navigate('products-list') },\n { id: 'product-categories', label: t('registry.product-categories'), active: view === 'product-categories', onClick: () => navigate('product-categories') },\n { id: 'bulk-products', label: 'Alteração em massa', active: view === 'bulk-products', onClick: () => navigate('bulk-products') },\n ],\n } as ModuleNavItem] : []),\n // «Inventário» é a CONTAGEM, e não um agrupamento: é assim que a palavra é\n // usada em quem veio do V1 — «vou fazer o inventário» quer dizer ir à\n // prateleira conferir. O saldo que o sistema calcula sozinho é o Resumo, e\n // ele abre o módulo lá em cima.\n {\n // DUAS ABAS, como no V1: o Painel diz QUANTO HÁ; as Contagens dizem o\n // que já foi conferido. O inventário abria direto na segunda, e a\n // pergunta que todo mundo faz primeiro não tinha tela.\n id: 'inventory', label: t('inventory.nav.inventory'), icon: 'ClipboardCheck',\n active: view === 'stock-panel' || view.startsWith('stock-counts'),\n children: [\n { id: 'stock-panel', label: t('inventory.nav.panel'), defaultChild: true, active: view === 'stock-panel', onClick: () => navigate('stock-panel') },\n { id: 'stock-counts', label: t('inventory.nav.counts'), active: view.startsWith('stock-counts'), onClick: () => navigate('stock-counts') },\n ],\n },\n // MOVIMENTAÇÕES É UMA LINHA SÓ, e ela leva direto para a lista.\n //\n // Entrada e saída eram filhas «ação» da aba: um grupo que abre para\n // oferecer dois formulários e o destino real no meio deles. Quem clica em\n // «Movimentações» quer ver o que entrou e o que saiu — lançar é o botão\n // que a própria lista já tem no cabeçalho, e é lá que a ação pertence.\n {\n id: 'stock-history', label: t('inventory.nav.stock'), icon: 'ArrowUpCircle',\n active: view === 'stock-history' || view === 'stock-entry' || view === 'stock-exit',\n onClick: () => navigate('stock-history'),\n },\n // ── Linha própria, como no V1 ────────────────────────────────────────\n //\n // Estas quatro moravam dentro de um grupo «Reposição», juntas pela pergunta\n // que respondem. Quem veio do V1 não as procura por pergunta: lá elas são\n // linhas do menu, com estes nomes, e um grupo a mais é um clique a mais\n // para descobrir que a tela mudou de lugar e não de função.\n //\n // Transferências vem logo depois de Movimentações porque é o mesmo assunto\n // — mercadoria andando —, e Indicadores depois dela porque é de saldo que\n // ele fala. A Ficha Técnica fecha o bloco, vizinha das Receitas: a receita\n // diz do que o prato é feito, a ficha diz quanto ele custa e quanto a\n // panela rende.\n { id: 'transfers', label: 'Transferências', icon: 'ArrowLeftRight', active: view === 'transfers', onClick: () => navigate('transfers') },\n { id: 'stock-indicators', label: 'Indicadores', icon: 'Target', active: view === 'stock-indicators', onClick: () => navigate('stock-indicators') },\n ...(house.requisitions ? [{ id: 'requisitions', label: 'Requisições', icon: 'ClipboardList', active: view === 'requisitions', onClick: () => navigate('requisitions') }] : []),\n // Fichas Técnicas sits here, after Requisições, as in V1 (pushed below\n // only when the house uses recipes).\n ...(config.modules.recipes ? [{\n // The app's own label wins when it picked one; otherwise the dictionary.\n id: 'recipes',\n label: config.labels.recipes && config.labels.recipes !== 'Recipes' ? config.labels.recipes : t('inventory.nav.recipes'),\n icon: 'BookOpen',\n // One entry, as in V1: «Nova Ficha Técnica» is the list's own button.\n active: view === 'recipes' || view === 'recipes-list' || view.startsWith('products-recipe:'),\n onClick: () => navigate('recipes-list'),\n }] : []),\n // Auditoria de Uso fica FORA do Inventário: ela não pergunta quanto há,\n // pergunta se o que saiu bate com o que foi vendido. É a única tela daqui\n // que olha para o consumo e não para o saldo.\n //\n // \"Nova contagem\" não está na navegação: era uma AÇÃO dentro de um menu, e\n // a lista de contagens já tem o \"+\" no cabeçalho dela.\n ...(house.usageAudit ? [{\n id: 'stock-usage-audit', label: t('inventory.nav.usageAudit'), icon: 'ScanSearch',\n active: view === 'stock-usage-audit',\n onClick: () => navigate('stock-usage-audit'),\n }] : []),\n // Produção fica de fora por decisão do founder: são seis telas e um assunto\n // próprio, não um buraco do estoque.\n //\n // «Locais» e não «Cadastros»: cadastro é o que TODA tela desta lista faz.\n // O que junta estas duas é o lugar físico — onde a mercadoria está e a que\n // temperatura ela está lá. A alteração em massa saiu daqui: ela mexe no\n // catálogo, não no armazém, e agora mora com os Produtos.\n {\n id: 'stock-setup', label: 'Locais', icon: 'Warehouse',\n active: ['stock-locations', 'temperature'].some((v) => view === v),\n children: [\n { id: 'stock-locations', label: 'Locais', defaultChild: true, active: view === 'stock-locations', onClick: () => navigate('stock-locations') },\n ...(house.temperature ? [{ id: 'temperature', label: 'Temperatura', active: view === 'temperature', onClick: () => navigate('temperature') }] : []),\n ],\n },\n ]\n\n\n // As abas emprestadas entram DEPOIS das próprias, na ordem em que o app as\n // passou. Entrada de Notas é a primeira delas.\n for (const extra of config.extraViews) {\n if (house.hiddenViews.includes(extra.id)) continue\n const own = [extra.id, ...(extra.children ?? []).map((c) => c.id)]\n const hits = (id: string) => view === id || view.startsWith(`${id}/`) || view.startsWith(`${id}:`)\n items.push({\n id: extra.id,\n label: extra.label,\n icon: extra.icon,\n active: own.some(hits),\n // Com filhos, o PAI não navega — quem navega é o filho padrão, como o grupo\n // «Estoque» já faz com `stock-history`. Dar `onClick` ao pai E injetá-lo\n // como primeiro filho deslocava a pílula em um: a tela certa aparecia com o\n // nome da vizinha em destaque.\n ...(extra.children?.length\n ? {\n children: [\n { id: extra.id, label: extra.defaultChildLabel ?? 'Entrada', defaultChild: true, active: hits(extra.id), onClick: () => navigate(extra.id) },\n ...extra.children.map((c) => ({ id: c.id, label: c.label, active: hits(c.id), onClick: () => navigate(c.id) })),\n ],\n }\n : { onClick: () => navigate(extra.id) }),\n })\n }\n\n return items\n}\n\nexport function InventoryPage({ config: appConfig, provider, store, registries }: {\n config: ResolvedInventoryConfig\n provider: InventoryDataProvider\n store: StoreApi<InventoryUIState>\n registries?: PluginRegistryDef[]\n}) {\n const t = useTranslation()\n // Receita é DECISÃO DA CASA. O aplicativo diz se OFERECE ficha técnica; a\n // conta diz se usa. `&&` e não `??`: o que o pacote não oferece o toggle não\n // ressuscita. Ver INVENTORY_MODULE_DEFAULTS.\n const houseModules = useInventoryHouseModules()\n const recipesOn = houseModules.get('recipes')\n const config = useMemo<ResolvedInventoryConfig>(\n () => appConfig.modules.recipes && recipesOn\n ? appConfig\n : { ...appConfig, modules: { ...appConfig.modules, recipes: false } },\n [appConfig, recipesOn],\n )\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, 'products-recipe': 1,\n settings: 1,\n }, 'dashboard')\n\n const checkExistingData = React.useCallback(\n async () => (await provider.getProducts({ pageSize: 1 })).total > 0,\n [provider],\n )\n const onboarding = usePluginOnboardingGate('saas-core:inventory-onboarded', checkExistingData)\n\n const isSettings = view === 'settings'\n const isSummary = view === 'dashboard' || view === ''\n const nav = buildNav(config, view, navigate, t, {\n requisitions: houseModules.get('requisitions'),\n usageAudit: houseModules.get('usageAudit'),\n temperature: houseModules.get('temperature'),\n hiddenViews: houseModules.get('hiddenViews'),\n })\n\n const completeOnboarding = React.useCallback(async () => {\n await provider.ensureReferenceData?.()\n onboarding.complete()\n }, [provider, onboarding.complete])\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 (isSummary && onboarding.status === 'checking') {\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <PluginOnboardingGateSkeleton />\n </InventoryContextProvider>\n )\n }\n\n if (isSummary && onboarding.status === 'needed') {\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 config={appConfig} />}\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}`)} onOpenTab={(tab) => navigate(`products-${tab}:${id}`)} /> },\n { id: 'products-detail', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n // Every tab writes `/products/<id>/<tab>` into the URL, so each of those\n // links has to come back to the same page with that tab open. Only\n // `stock` had a route: reloading on any other tab fell through to the\n // module's first screen.\n ...['stock', 'variants', 'barcodes', 'complements', ...config.productDetailTabs.map((tab) => tab.id)].map((tab) => ({\n id: `products-${tab}`,\n render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} initialTab={tab} onBack={() => navigate('products-list')} onEdit={() => navigate(`products-edit:${id}`)} />,\n })),\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-panel', render: () => <StockPanelView /> },\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 onOpenProduct={(pid) => navigate(`products-recipe:${pid}`)} /> },\n { id: 'recipes-list', render: () => <RecipesView onOpenProduct={(pid) => navigate(`products-recipe:${pid}`)} /> },\n // The sheet lives in the product, on its tab — the same page Produtos opens.\n { id: 'products-recipe', render: ({ id }: { id?: string }) => <ProductDetailView productId={id!} initialTab=\"recipe\" onBack={() => navigate('recipes-list')} onEdit={() => navigate(`products-edit:${id}`)} /> },\n // Telas emprestadas por outro plugin — hoje a Entrada de Notas, que é assunto\n // de estoque e não linha de rail (no V1: Estoque → Notas Fiscais → Entrada).\n ...config.extraViews.flatMap((v) => [\n { id: v.id, render: () => <>{v.render()}</> },\n ...(v.children ?? []).map((c) => ({ id: c.id, render: () => <>{c.render()}</> })),\n ]),\n // As telas que ainda não existem. Cada uma diz o que falta e o tamanho do\n // buraco, medido no V1 — ver `./GapScreens`.\n // Categorias e Locais NÃO são «em breve»: o plugin já declara os dois como\n // cadastro (`data/registries`), e eles só viviam atrás de Configurações —\n // onde ninguém procura o lugar onde a carne fica. `RegistryCrudView` é o\n // mesmo CRUD que a página de ajustes desenha, agora na aba onde o assunto\n // está. Sem o cadastro declarado (um app que corte o registro), cai no\n // «em breve» de antes.\n //\n // Sem `embedded`: aqui o cadastro É a tela — a aba do módulo leva a ele e a\n // nada mais. `embedded` é para o cadastro montado NO MEIO de outra tela, ao\n // lado de outros blocos, e o que ele faz é tirar o «Adicionar» da barra do\n // topo e largá-lo numa fileira própria, encostado à direita do corpo. Com\n // isso, Locais e Categorias eram as duas únicas listas do Estoque cujo botão\n // de criar ficava em outro lugar que o de Produtos e o de Contagens.\n // The module writes a view id as a path (`product-categories` is\n // `/product/categories`), so the registry's base path and its own\n // new/edit addresses have to be spelled the same way or \"New\" lands on 404.\n ...['', '-new', '-edit', '-detail'].flatMap((suffix) => [\n { id: `product-categories${suffix}`, render: () => {\n const reg = registries?.find((r) => r.id === 'product-categories')\n return reg ? <RegistryCrudView registry={reg} basePath=\"/inventory/product/categories\" /> : <ComingSoon title=\"Categorias\" summary=\"Como o catálogo se agrupa.\" v1Path=\"Estoque → Produtos → Categorias\" missing={['Este aplicativo não declarou o cadastro de categorias']} />\n } },\n { id: `stock-locations${suffix}`, render: () => {\n const reg = registries?.find((r) => r.id === 'stock-locations')\n return reg ? <RegistryCrudView registry={reg} basePath=\"/inventory/stock/locations\" /> : <StockLocationsView />\n } },\n ]),\n { id: 'temperature', render: () => <TemperatureView /> },\n { id: 'bulk-products', render: () => <BulkProductEditView /> },\n { id: 'stock-indicators', render: () => <StockIndicatorsView /> },\n { id: 'transfers', render: () => <TransfersView /> },\n { id: 'requisitions', render: () => <RequisitionsView /> },\n // The old placeholder's address lands on the real list.\n { id: 'technical-sheet', render: () => <RecipesView onOpenProduct={(pid) => navigate(`products-recipe:${pid}`)} /> },\n { id: 'dashboard', render: () => <DashboardView /> },\n ], 'dashboard')\n\n return (\n <InventoryContextProvider config={config} provider={provider} store={store}>\n <ModulePage\n navVariant={config.moduleNav}\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 from 'react'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\nimport { RelatedListTab } from '@fayz-ai/admin'\n\n/** V1 stock_locations → plg_inventory_stock_locations. Deleting deactivates, as in V1. */\nexport const stockLocationEntity: EntityDef = {\n name: 'Local de estoque',\n namePlural: 'Locais de estoque',\n icon: 'Package',\n displayField: 'name',\n defaultSort: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'O local', columns: 2 }, { ...RECORD_GROUP }],\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, searchable: true, group: 'identity' },\n { key: 'description', label: 'Descrição', type: 'text', showInTable: true, group: 'identity', span: 2 },\n { key: 'code', label: 'Código', type: 'text', group: 'identity' },\n ...recordRailFields({ tagsTable: 'plg_inventory_stock_locations', activeLabel: 'Ativo', unitRequired: true })\n .filter((f) => f.key !== 'tags' && f.key !== 'notes'),\n ],\n data: {\n table: 'plg_inventory_stock_locations',\n schema: 'public',\n tenantScoped: true,\n searchColumns: ['name', 'description', 'code'],\n },\n}\n\nexport function UnitStockLocationsWidget({ item }: { item?: { id?: string } }) {\n if (!item?.id) return null\n return (\n <RelatedListTab\n item={item}\n entityDef={stockLocationEntity}\n parentTabId=\"locations\"\n related={{\n id: 'stock-locations', label: 'Locais de estoque', entity: stockLocationEntity, foreignKey: 'unitId',\n emptyHint: 'Nenhum local de estoque nesta unidade ainda. Toda entrada e saída precisa dizer de onde.',\n }}\n />\n )\n}\n","import React, { useEffect } from 'react'\nimport { ArrowUpRight, ArrowDownRight, AlertTriangle, PackageX } 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, Badge, Skeleton,\n defineKpiWidget, defineCustomWidget,\n} from '@fayz-ai/ui'\nimport { InventoryContextProvider, useInventoryConfig, useInventoryStore, formatCurrency, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { InventoryUIState } from '@fayz-ai/inventory/store'\nimport { noProductHasMinimum } from '@fayz-ai/inventory/domain/stock'\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\n/**\n * O número que explica os outros.\n *\n * Com o depósito vazio e nenhum mínimo cadastrado, \"Estoque Baixo\" marca ZERO —\n * e o cartão mais importante do painel vira o mais enganoso. Este conta quantos\n * produtos ainda não têm de que estar abaixo. O V1 resolve o mesmo caso ao\n * contrário: trata mínimo 0 como alerta, 93% do catálogo entra na reposição\n * urgente e ninguém olha mais a lista.\n */\nfunction NoMinimumKpi() {\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n const n = summary?.noMinimumCount ?? 0\n return (\n <KpiCard\n label=\"Sem mínimo definido\"\n icon=\"AlertTriangle\"\n value={String(n)}\n sub={n > 0 ? 'Não entram no alerta de estoque baixo' : 'Todo produto tem mínimo'}\n />\n )\n}\n\nfunction RestockRowSkeleton() {\n return (\n <ul className=\"space-y-2\">\n {[0, 1, 2].map((i) => (\n <li key={i} className=\"flex items-center gap-3\">\n <Skeleton className=\"h-4 w-40\" />\n <span className=\"flex-1\" />\n <Skeleton className=\"h-4 w-16\" />\n </li>\n ))}\n </ul>\n )\n}\n\n/** Quantidade com a unidade de medida junto — o número sozinho não informa. */\nfunction qty(value: number, unit?: string): string {\n const n = value.toLocaleString('pt-BR', { maximumFractionDigits: 3 })\n return unit ? `${n} ${unit}` : n\n}\n\n/**\n * O que precisa de compra, com o MOTIVO em cada linha.\n *\n * \"Abaixo do mínimo\" vem antes de \"sem estoque\": o abaixo do mínimo é uma\n * compra que a casa já decidiu que precisa fazer; o zerado pode ser um cadastro\n * que nunca entrou em uso — e aqui são 162 de 169, o que seria uma lista de\n * alarme falso do tamanho do catálogo.\n */\nfunction RestockPanel() {\n const rows = useInventoryStore((s) => s.restock)\n const summary = useInventoryStore((s) => s.summary)\n const fetchRestock = useInventoryStore((s) => s.fetchRestock)\n useEnsureSummary()\n useEffect(() => { void fetchRestock() }, [])\n\n const belowMinimum = (rows ?? []).filter((r) => r.reason === 'below-minimum')\n const outOfStock = (rows ?? []).filter((r) => r.reason === 'out-of-stock')\n const nobodyHasMinimum = noProductHasMinimum(summary)\n\n return (\n <Card>\n <CardHeader><CardTitle>Precisa de reposição</CardTitle></CardHeader>\n <CardContent>\n {rows === null ? (\n <RestockRowSkeleton />\n ) : nobodyHasMinimum ? (\n // Sem nenhum mínimo cadastrado esta lista não é um alerta: é o\n // catálogo inteiro. Dizer o que falta vale mais do que listá-lo.\n <div className=\"text-sm\">\n <p className=\"font-medium\">Nenhum produto tem estoque mínimo definido.</p>\n <p className=\"mt-1 text-muted-foreground\">\n Sem o mínimo na ficha do produto não há reposição a calcular — o alerta\n de estoque baixo fica em zero mesmo com o depósito vazio.\n {/* O número vem do RESUMO, não do tamanho da lista: a lista é\n cortada em 50 e escrever o corte como se fosse o total é\n mentir com precisão — aqui daria \"50\" onde são 162. */}\n {(summary?.outOfStockCount ?? 0) > 0 && ` Hoje ${summary!.outOfStockCount === 1 ? 'há 1 produto' : `há ${summary!.outOfStockCount} produtos`} com saldo zerado.`}\n </p>\n </div>\n ) : rows.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n Nada a repor: todo produto está acima do mínimo.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {[...belowMinimum, ...outOfStock].slice(0, 8).map((row) => (\n <li key={row.productId} className=\"flex items-center gap-3 text-sm\">\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate\">{row.name}</span>\n {row.categoryName && (\n <span className=\"block truncate text-xs text-muted-foreground\">{row.categoryName}</span>\n )}\n </span>\n {row.reason === 'below-minimum' ? (\n <Badge variant=\"secondary\" className=\"gap-1 shrink-0\">\n <AlertTriangle className=\"h-3 w-3\" aria-hidden=\"true\" />\n {qty(row.currentQuantity, row.unit)} de {qty(row.minQuantity, row.unit)}\n </Badge>\n ) : (\n <Badge variant=\"outline\" className=\"gap-1 shrink-0\">\n <PackageX className=\"h-3 w-3\" aria-hidden=\"true\" />\n Sem estoque\n </Badge>\n )}\n </li>\n ))}\n </ul>\n )}\n </CardContent>\n </Card>\n )\n}\n\n/**\n * A divisão do catálogo — barras ordenadas, UM matiz, com ênfase.\n *\n * Não é rosca: oito classes que todas significam alguma coisa passam do que uma\n * pizza consegue separar, e a fatia dominante aqui é \"Sem categoria\", que não é\n * uma categoria — é um cadastro por fazer. Em rosca ela vira só a maior fatia;\n * em barras com ênfase ela diz o que custa. A cor não carrega identidade\n * (série única, sem legenda): o rótulo carrega, e o texto usa tinta de texto.\n */\nfunction CategoryMixPanel() {\n const mix = useInventoryStore((s) => s.categoryMix)\n const fetchMix = useInventoryStore((s) => s.fetchCategoryMix)\n useEffect(() => { void fetchMix() }, [])\n\n const total = (mix ?? []).reduce((sum, c) => sum + c.count, 0)\n const uncategorized = (mix ?? []).find((c) => c.categoryId === null)\n\n return (\n <Card>\n <CardHeader><CardTitle>Produtos por categoria</CardTitle></CardHeader>\n <CardContent>\n {mix === null ? (\n <RestockRowSkeleton />\n ) : total === 0 ? (\n <p className=\"text-sm text-muted-foreground\">Nenhum produto ativo para distribuir.</p>\n ) : (\n <>\n <ul className=\"space-y-2\">\n {mix.slice(0, 8).map((row) => {\n const pct = Math.round((row.count / total) * 100)\n const isGap = row.categoryId === null\n return (\n <li key={row.categoryId ?? 'none'} className=\"flex items-center gap-3 text-sm\">\n <span className=\"w-40 shrink-0 truncate\" title={row.name}>{row.name}</span>\n <span\n className=\"relative h-2 flex-1 overflow-hidden rounded-full bg-muted\"\n aria-hidden=\"true\"\n >\n <span\n className={isGap ? 'absolute inset-y-0 left-0 rounded-full bg-muted-foreground/60' : 'absolute inset-y-0 left-0 rounded-full bg-primary'}\n style={{ width: `${pct}%` }}\n />\n </span>\n {/* Rótulo direto em todas as linhas: são oito, e ler um\n eixo para oito valores é trabalho que a tela pode poupar. */}\n <span className=\"w-20 shrink-0 text-right tabular-nums text-muted-foreground\">\n {row.count} · {pct}%\n </span>\n </li>\n )\n })}\n </ul>\n {uncategorized && uncategorized.count > 0 && (\n <p className=\"mt-3 text-xs text-muted-foreground\">\n {uncategorized.count} de {total} produtos ainda não têm categoria — é o\n que impede este painel, os filtros e as isenções de taxa de dizerem\n algo útil.\n </p>\n )}\n </>\n )}\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 // Escondido na home global (é diagnóstico de cadastro, não manchete do\n // negócio) e visível no painel do estoque, que é onde se conserta.\n defineKpiWidget({ id: 'inventory.kpi.no-minimum', title: 'Sem mínimo definido', domain: 'inventory', defaultOrder: 4, defaultVisible: false, component: withCtx(NoMinimumKpi) }),\n defineCustomWidget({ id: 'inventory.panel.recent-activity', title: 'inventory.dashboard.recentActivity', domain: 'inventory', span: 2, defaultOrder: 10, surfaces: ['plugin-home'], component: withCtx(RecentActivityPanel) }),\n defineCustomWidget({ id: 'inventory.panel.restock', title: 'Precisa de reposição', domain: 'inventory', span: 2, defaultOrder: 11, surfaces: ['plugin-home'], component: withCtx(RestockPanel) }),\n defineCustomWidget({ id: 'inventory.panel.category-mix', title: 'Produtos por categoria', domain: 'inventory', span: 2, defaultOrder: 12, surfaces: ['plugin-home'], component: withCtx(CategoryMixPanel) }),\n ]\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\nimport { PRODUCT_CATEGORY_KIND, T } from '@fayz-ai/inventory/data/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 // Declares the supplier as someone the house pays, which is what keeps\n // the \"Bank accounts\" section on the record.\n { key: 'payeeAccount', label: 'Bank account', type: 'bank', showInTable: false, showInDetail: false },\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 formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'abbreviation', label: 'Abbreviation', type: 'text', required: true, showInTable: true, group: 'identity' },\n ...recordRailFields({ tagsTable: T.measurementUnits, activeLabel: 'Ativo', unit: false }),\n ],\n data: { table: T.measurementUnits, tenantScoped: true },\n}\n\nconst productCategoryEntity: EntityDef = {\n name: 'Product Category',\n namePlural: 'Product Categories',\n // O botao de criar interpola o SUBSTANTIVO, e `name` e um literal ingles:\n // sem estas chaves o CrudListView omite o nome e escreve so «Adicionar»,\n // enquanto a lista ao lado escreve «Novo Produto». Ver EntityDef.nameKey.\n nameKey: 'inventory.entity.productCategory',\n namePluralKey: 'inventory.entity.productCategory.plural',\n icon: 'Tag',\n displayField: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'parentId', label: 'Parent', type: 'text', showInTable: false, group: 'identity' },\n ...recordRailFields({ tagsTable: T.productCategories, activeLabel: 'Ativo', unit: false }),\n ],\n data: {\n table: T.productCategories,\n schema: 'public',\n tenantScoped: true,\n filters: { kind: PRODUCT_CATEGORY_KIND },\n defaults: { kind: PRODUCT_CATEGORY_KIND },\n },\n}\n\n// Em português porque a tela é: as vizinhas desta lista («Ativo», «Unidade»,\n// «Identificação») já estavam traduzidas, e duas colunas em inglês no meio\n// delas leem como campo de outro sistema.\nconst stockLocationEntity: EntityDef = {\n name: 'Local de Estoque',\n namePlural: 'Locais de Estoque',\n nameKey: 'inventory.entity.stockLocation',\n namePluralKey: 'inventory.entity.stockLocation.plural',\n icon: 'Warehouse',\n displayField: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'description', label: 'Descrição', type: 'textarea', showInTable: true, group: 'identity' },\n ...recordRailFields({ tagsTable: T.stockLocations, activeLabel: 'Ativo', unit: 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: 'Onde a mercadoria fica guardada',\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 // O tour navega até o cadastro de produto; os passos sem âncora ficam de\n // briefing (a tela é um CRUD genérico, sem campos ancoráveis por enquanto).\n steps: [\n { do: 'O Estoque mora aqui.', anchor: 'nav./inventory', route: '/inventory' },\n { do: 'Produtos ficam neste menu.', anchor: 'modnav.products', route: '/inventory/products/list' },\n { do: 'Cadastre um produto novo aqui.', anchor: 'action.new-product', route: '/inventory/products/list' },\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 // Navega até a tela de entrada; a `practice` deixa a pessoa dar a entrada.\n steps: [\n { do: 'O Estoque mora aqui.', anchor: 'nav./inventory', route: '/inventory' },\n { do: 'Abra Entrada neste menu para lançar a compra que chegou.', anchor: 'modnav.stock-entry', route: '/inventory/stock/entry' },\n { do: 'Saída é para o que foi descartado, perdido ou usado fora de um atendimento.' },\n { do: 'O histórico mostra tudo, inclusive o que o sistema lançou sozinho.' },\n ],\n practice: [\n { anchor: 'inventory.entry-product', label: 'Escolha o produto que chegou' },\n { anchor: 'inventory.entry-save', label: 'Confirme a entrada', final: true },\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: 'Fichas Técnicas',\n about:\n 'A receita de cada produto que a casa produz: os insumos e as quantidades, por componente e estação, com o custo calculado e o CMV contra o preço de venda.',\n route: '/inventory/recipes/list',\n requires: [\n {\n title: 'Insumos cadastrados',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'o campo Insumo da ficha encontra o item ao digitar (produto com Insumo ou Intermediário ligado)',\n },\n {\n title: 'Custo de cada insumo',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'a coluna Custo da linha mostra R$ em vez de —; o lápis da própria ficha resolve',\n },\n {\n title: 'Preço de venda no produto da ficha',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'o CMV da ficha mostra % em vez de —',\n },\n ],\n steps: [\n { do: 'Estoque › Fichas Técnicas › Nova Ficha Técnica, e escolha o produto.', route: '/inventory/recipes/list' },\n { do: 'Confira Rendimento, Unidade e Tipo de rendimento: Porção quando a ficha é 1 unidade vendida, Lote quando ela produz o rendimento.' },\n { do: 'Adicionar Grupo para cada componente (ex.: Preparo da Costela, Montagem) e escolha a estação.' },\n { do: 'Em cada componente, Adicionar Item: insumo, quantidade e unidade. Custo — = clique no lápis e informe o preço.' },\n { do: 'Salvar Ficha Técnica. O custo por unidade vira o custo do produto.' },\n ],\n rules: [\n 'Ter ficha é ser produzido: salvar liga «Produto Produzido» no produto.',\n 'O custo da ficha substitui o custo do produto, e é ele que outra ficha lê quando este produto entra como insumo.',\n 'Saídas da produção: ou todas as aproveitáveis têm %, somando 100, ou todas ficam em branco (rateio pelo valor de mercado).',\n 'A sugestão da IA preenche a tela e não grava nada; ela substitui os componentes que estavam lá.',\n ],\n answers: [\n 'Por que o produto não tem a aba Ficha Técnica?',\n 'Qual a diferença entre rendimento Porção e Lote?',\n 'Por que o insumo aparece com custo —?',\n 'Salvei a ficha e o custo do produto mudou sozinho. É normal?',\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 '@fayz-ai/inventory/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.nav.panel\": \"Panel\",\n \"inventory.panel.columnProduct\": \"Product\",\n \"inventory.panel.columnLocation\": \"Location\",\n \"inventory.panel.columnBatch\": \"Batch\",\n \"inventory.panel.columnExpiry\": \"Expiry\",\n \"inventory.panel.columnQuantity\": \"Qty / min\",\n \"inventory.panel.columnValue\": \"Value\",\n \"inventory.panel.empty\": \"No stock position for this selection.\",\n \"inventory.panel.totalLines\": \"Lines\",\n \"inventory.panel.totalValue\": \"Stock value\",\n \"inventory.panel.unsupported\": \"This app does not expose the stock panel.\",\n \"inventory.filters.stockState\": \"Stock status\",\n \"inventory.filters.health.negative\": \"Negative\",\n \"inventory.filters.health.below_min\": \"Below min\",\n \"inventory.filters.health.zero\": \"Zero\",\n \"inventory.filters.health.ok\": \"OK\",\n \"inventory.filters.expiry\": \"Expiry\",\n \"inventory.filters.expiry.all\": \"All\",\n \"inventory.filters.expiry.expired\": \"Expired\",\n \"inventory.filters.expiry.le30\": \"Expires in 30 days\",\n \"inventory.filters.expiry.le60\": \"Expires in 60 days\",\n \"inventory.filters.expiry.le90\": \"Expires in 90 days\",\n \"inventory.filters.expiry.none\": \"No expiry\",\n \"inventory.filters.batchPlaceholder\": \"Batch\",\n \"inventory.filters.productPlaceholder\": \"Search product...\",\n \"inventory.filters.countState\": \"Count state\",\n \"inventory.filters.countAll\": \"All\",\n \"inventory.filters.countPending\": \"To count\",\n \"inventory.filters.countDone\": \"Counted\",\n \"inventory.filters.itemSearchPlaceholder\": \"Search product or code...\",\n \"inventory.filters.title\": \"Filters\",\n \"inventory.filters.apply\": \"Search\",\n \"inventory.filters.pending\": \"Filters changed\",\n \"inventory.filters.pendingHint\": \"The list still shows the previous selection. Click Search to apply.\",\n \"inventory.filters.clear\": \"Clear\",\n \"inventory.filters.more\": \"More filters\",\n \"inventory.filters.less\": \"Fewer filters\",\n \"inventory.filters.from\": \"From\",\n \"inventory.filters.to\": \"To\",\n \"inventory.filters.allTypes\": \"All types\",\n \"inventory.filters.location\": \"Location\",\n \"inventory.filters.allLocations\": \"All locations\",\n \"inventory.filters.category\": \"Category\",\n \"inventory.filters.allCategories\": \"All categories\",\n \"inventory.filters.kind\": \"Item type\",\n \"inventory.filters.allKinds\": \"All\",\n \"inventory.filters.status\": \"Status\",\n \"inventory.filters.allStatuses\": \"All\",\n \"inventory.stock.pendingRetry\": \"Confirmation is pending. Do not create another entry. Retry the same details before leaving this screen.\",\n \"inventory.stock.refreshAfterCommit\": \"Movement recorded. Refresh the screen to see the balance.\",\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 \"inventory.entity.stockLocation\": \"Stock Location\",\n \"inventory.entity.stockLocation.plural\": \"Stock Locations\",\n \"inventory.entity.productCategory\": \"Category\",\n \"inventory.entity.productCategory.plural\": \"Categories\",\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\": \"Summary\",\n \"inventory.nav.entry\": \"Entry\",\n \"inventory.nav.exit\": \"Exit\",\n \"inventory.nav.history\": \"History\",\n \"inventory.nav.inventory\": \"Inventory\",\n \"inventory.nav.list\": \"List\",\n \"inventory.nav.new\": \"New\",\n \"inventory.nav.products\": \"Products\",\n \"inventory.nav.stock\": \"Movements\",\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 produced products yet\",\n \"inventory.recipes.exporting\": \"Building the recipes spreadsheet…\",\n \"inventory.recipes.exported\": \"Spreadsheet downloaded\",\n \"inventory.sheet.print\": \"Print\",\n \"inventory.sheet.printSaveFirst\": \"Save the sheet before printing\",\n \"inventory.recipes.noCategory\": \"No category\",\n \"inventory.recipes.filterKind\": \"Type\",\n \"inventory.recipes.filterKindAll\": \"All types\",\n \"inventory.recipes.kindSale\": \"Sale\",\n \"inventory.recipes.kindIntermediate\": \"Intermediate\",\n \"inventory.recipes.filterCategory\": \"Category\",\n \"inventory.recipes.filterCategoryAll\": \"All categories\",\n \"inventory.recipes.filterCmv\": \"CMV\",\n \"inventory.recipes.filterCmvAll\": \"Any CMV\",\n \"inventory.recipes.cmvHigh\": \"CMV above {{pct}}%\",\n \"inventory.recipes.cmvGood\": \"Good CMV (below {{pct}}%)\",\n \"inventory.recipes.cmvAttention\": \"CMV watch ({{from}}–{{to}}%)\",\n \"inventory.recipes.cmvNone\": \"No CMV\",\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.minimum\": \"Minimum\",\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.modules\": \"Modules\",\n \"inventory.settings.modulesDesc\": \"What this house shows inside Inventory\",\n \"inventory.settings.recipes\": \"Recipes\",\n \"inventory.settings.recipesDesc\": \"The bill of materials that says what each product consumes\",\n \"inventory.settings.requisitions\": \"Requisitions\",\n \"inventory.settings.requisitionsDesc\": \"Internal requests for material between areas\",\n \"inventory.settings.usageAuditDesc\": \"What left stock against what was sold\",\n \"inventory.settings.temperature\": \"Temperature\",\n \"inventory.settings.temperatureDesc\": \"Temperature log for refrigerated 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 // Product fichas — ported from the V1 product form (the per-type tabs).\n \"inventory.productForm.commissionPercent\": \"Commission % (sale)\",\n \"inventory.productForm.commissionPercentHint\": \"What the professional earns when selling this product.\",\n \"inventory.productForm.chartAccount\": \"Chart of accounts\",\n \"inventory.productForm.avgPurchasePrice\": \"Average purchase price\",\n \"inventory.productForm.avgPurchasePriceHint\": \"Rewritten on every stock entry.\",\n \"inventory.productForm.packaging\": \"Packaging and conversions\",\n \"inventory.productForm.packagingDesc\": \"How the house buys, when that differs from how it counts.\",\n \"inventory.productForm.contentPerUnit\": \"Content per unit\",\n \"inventory.productForm.contentPerUnitHint\": \"How much fits in ONE stock unit (a bottle holds 300 ml).\",\n \"inventory.productForm.contentUnit\": \"Content unit\",\n \"inventory.productForm.purchaseUnit\": \"Purchase unit\",\n \"inventory.productForm.conversionFactor\": \"Quantity per package\",\n \"inventory.productForm.conversionFactorHint\": \"How many stock units come in one purchase unit.\",\n \"inventory.productForm.flagIngredient\": \"Ingredient\",\n \"inventory.productForm.flagIngredientHint\": \"Shows up in recipes.\",\n \"inventory.productForm.flagForSale\": \"For sale\",\n \"inventory.productForm.flagForSaleHint\": \"Menu, POS, catalogue.\",\n \"inventory.productForm.flagIntermediate\": \"Intermediate\",\n \"inventory.productForm.flagIntermediateHint\": \"Made to be used later (sauce, dough).\",\n \"inventory.productForm.flagAsset\": \"Asset\",\n \"inventory.productForm.flagAssetHint\": \"Equipment: it goes on the balance sheet, it is not consumed.\",\n \"inventory.productForm.flagProduced\": \"Produced product\",\n \"inventory.productForm.flagProducedHint\": \"Comes from a recipe — enables the recipe sheet.\",\n \"inventory.productForm.flagResale\": \"Resale\",\n \"inventory.productForm.flagResaleHint\": \"Goods meant to be resold to the customer.\",\n \"inventory.productForm.flagTracked\": \"High value / labelled\",\n \"inventory.productForm.flagTrackedHint\": \"Each unit is tracked individually.\",\n \"inventory.productForm.professionalResalePrice\": \"Professional resale price\",\n \"inventory.productForm.professionalResalePriceHint\": \"Charged when the professional resells to the end customer.\",\n \"inventory.productForm.requireBatch\": \"Require batch on entry\",\n \"inventory.productForm.requireBatchHint\": \"Blocks stock entry without a batch number.\",\n \"inventory.productForm.requireExpiry\": \"Require expiry on entry\",\n \"inventory.productForm.requireExpiryHint\": \"Blocks stock entry without an expiry date.\",\n \"inventory.productForm.notes\": \"Notes\",\n \"inventory.productForm.ingredientSection\": \"Ingredient\",\n \"inventory.productForm.ingredientSectionDesc\": \"What purchasing needs to restock in time.\",\n \"inventory.productForm.ingReorderPoint\": \"Reorder point\",\n \"inventory.productForm.ingReorderPointHint\": \"Sits ABOVE the minimum: the warning that still arrives in time to buy.\",\n \"inventory.productForm.ingLeadTime\": \"Lead time (days)\",\n \"inventory.productForm.ingShelfLife\": \"Shelf life (days)\",\n \"inventory.productForm.ingStorageTemp\": \"Storage temperature\",\n \"inventory.productForm.saleSection\": \"Sale\",\n \"inventory.productForm.saleSectionDesc\": \"What the menu and the counter show the customer.\",\n \"inventory.productForm.salePrepTime\": \"Prep time (min)\",\n \"inventory.productForm.saleServes\": \"Serves (people)\",\n \"inventory.productForm.saleCalories\": \"Calories (kcal)\",\n \"inventory.productForm.saleMenuDescription\": \"Menu description\",\n \"inventory.productForm.saleAllergens\": \"Allergens\",\n \"inventory.productForm.saleAllergensPlaceholder\": \"Contains gluten, lactose\",\n \"inventory.productForm.saleSoldByWeight\": \"Sold by weight\",\n \"inventory.productForm.saleHighlightDelivery\": \"Highlight on delivery\",\n \"inventory.productForm.saleAvailableDelivery\": \"Available for delivery\",\n \"inventory.productForm.saleAvailableCounter\": \"Available at the counter\",\n \"inventory.productForm.saleChannelsSection\": \"Channel prices\",\n \"inventory.productForm.saleChannelsSectionDesc\": \"Leave a channel empty to use the base sale price.\",\n \"inventory.productForm.intermediateSection\": \"Intermediate\",\n \"inventory.productForm.intermediateSectionDesc\": \"What production needs to prepare the batch.\",\n \"inventory.productForm.intYield\": \"Yield (%)\",\n \"inventory.productForm.intPrepTime\": \"Prep time (min)\",\n \"inventory.productForm.intShelfLifeHours\": \"Shelf life after prep (h)\",\n \"inventory.productForm.intBatchSize\": \"Batch size\",\n \"inventory.productForm.intBatchUnit\": \"Batch unit\",\n \"inventory.productForm.intStorage\": \"Storage instructions\",\n \"inventory.productForm.assetSection\": \"Asset\",\n \"inventory.productForm.assetSectionDesc\": \"The equipment the house owns, and who answers for it.\",\n \"inventory.productForm.assetValue\": \"Asset value\",\n \"inventory.productForm.assetResidualValue\": \"Residual value\",\n \"inventory.productForm.assetUsefulLife\": \"Useful life (months)\",\n \"inventory.productForm.assetDepreciation\": \"Annual depreciation (%)\",\n \"inventory.productForm.assetSerial\": \"Serial number\",\n \"inventory.productForm.assetAcquisition\": \"Acquisition date\",\n \"inventory.productForm.assetWarranty\": \"Warranty until\",\n \"inventory.productForm.assetStatus\": \"Status\",\n \"inventory.productForm.assetLocation\": \"Location\",\n \"inventory.productForm.assetLocationPlaceholder\": \"Room 2, shelf B\",\n \"inventory.productForm.assetResponsible\": \"Responsible\",\n \"inventory.productForm.assetInsurance\": \"Insurance policy\",\n \"inventory.productForm.assetLastMaintenance\": \"Last maintenance\",\n \"inventory.productForm.assetNextMaintenance\": \"Next maintenance\",\n \"inventory.productForm.taxSection\": \"Tax\",\n \"inventory.productForm.taxSectionDesc\": \"What the invoice must say about this product. Empty means the tax group decides.\",\n \"inventory.productForm.taxGroup\": \"Tax group\",\n \"inventory.productForm.taxGroupHint\": \"Set up under Inventory › Invoices › Tax groups.\",\n \"inventory.productForm.ncmHint\": \"The product's invoice classification. It belongs to the product, never to the group.\",\n \"inventory.productForm.icmsOrigin\": \"ICMS origin\",\n \"inventory.productForm.icmsRate\": \"ICMS rate (%)\",\n \"inventory.productForm.cstHint\": \"CST has 2 digits. CSOSN has 3 and is set on the tax group, for Simples Nacional.\",\n \"inventory.productForm.pisRate\": \"PIS rate (%)\",\n \"inventory.productForm.cofinsRate\": \"COFINS rate (%)\",\n \"inventory.productForm.baseCalcMode\": \"Tax base mode\",\n \"inventory.productForm.benefitCode\": \"Tax benefit code (cBenef)\",\n \"inventory.productForm.povertyFund\": \"Poverty fund (%)\",\n \"inventory.productForm.ibsCbsSituation\": \"IBS and CBS — tax situation\",\n \"inventory.productForm.ibsCbsClassification\": \"IBS and CBS — tax classification\",\n \"inventory.productForm.classificationRequired\": \"Pick at least one classification for the product.\",\n \"inventory.productType.ingredient\": \"Ingredient\",\n \"inventory.productType.sale\": \"For sale\",\n \"inventory.productType.intermediate\": \"Intermediate\",\n \"inventory.productType.asset\": \"Asset\",\n \"inventory.variants.tab\": \"Variants\",\n \"inventory.variants.name\": \"Variant\",\n \"inventory.variants.namePlaceholder\": \"E.g. M, L, XL, Blue\",\n \"inventory.variants.sku\": \"SKU\",\n \"inventory.variants.skuPlaceholder\": \"Optional\",\n \"inventory.variants.default\": \"Default\",\n \"inventory.variants.empty\": \"No variants. The product is sold and stocked as a single item.\",\n \"inventory.variants.duplicate\": \"A variant with this name already exists.\",\n \"inventory.variants.loadFailed\": \"Could not load the variants.\",\n \"inventory.variants.saveFailed\": \"Could not save the variant.\",\n \"inventory.variants.unavailable\": \"Variants are not available in this workspace.\",\n \"inventory.variants.onHand\": \"{{count}} in stock\",\n \"inventory.barcodes.tab\": \"Barcodes\",\n \"inventory.barcodes.code\": \"Barcode\",\n \"inventory.barcodes.codePlaceholder\": \"Type or scan\",\n \"inventory.barcodes.type\": \"Type\",\n \"inventory.barcodes.description\": \"Description\",\n \"inventory.barcodes.descriptionPlaceholder\": \"500 ml pack\",\n \"inventory.barcodes.needCode\": \"Type or scan a code.\",\n \"inventory.barcodes.empty\": \"No barcode registered.\",\n \"inventory.barcodes.duplicate\": \"This code is already in use.\",\n \"inventory.barcodes.isPrimary\": \"Primary — this is what the label prints\",\n \"inventory.barcodes.makePrimary\": \"Make primary\",\n \"inventory.barcodes.removeTitle\": \"Remove this barcode?\",\n \"inventory.barcodes.unavailable\": \"Barcodes are unavailable in this environment.\",\n \"inventory.productRecipe.tab\": \"Recipe\",\n \"inventory.productRecipe.none\": \"This product has no recipe yet.\",\n \"inventory.productRecipe.noneHint\": \"The recipe says what the product is made of — cost and food-cost come from it.\",\n \"inventory.productRecipe.goToRecipes\": \"Go to Recipes\",\n \"inventory.productForm.classificationUnset\": \"Unclassified\",\n \"inventory.productForm.stepIdentity\": \"Identity\",\n \"inventory.productForm.stepClassification\": \"Classification\",\n \"inventory.productForm.stepPricing\": \"Pricing\",\n \"inventory.productForm.stepStock\": \"Stock\",\n \"inventory.productForm.stepInitialEntry\": \"Opening stock\",\n \"inventory.productForm.initialEntrySection\": \"Receive stock\",\n \"inventory.productForm.initialEntrySectionDesc\": \"Optional: record what is already on the shelf. Leave blank to receive later.\",\n \"inventory.productForm.initialQuantity\": \"Quantity on hand\",\n \"inventory.productForm.initialLocation\": \"Location\",\n \"inventory.productForm.initialLocationHint\": \"Blank uses the product's default location.\",\n \"inventory.productForm.initialUnitCost\": \"Unit cost\",\n \"inventory.productForm.initialUnitCostHint\": \"Blank uses the product's cost.\",\n \"inventory.productForm.initialBatch\": \"Batch\",\n \"inventory.productForm.initialExpiry\": \"Expiry date\",\n \"inventory.productForm.initialEntryFailed\": \"Product created, but the stock entry was not recorded. Receive it from the Stock tab.\",\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 recipe...\",\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.\",\n \"inventory.counts.incomplete\": \"Finish the count before closing\",\n \"inventory.counts.incompleteDescription\": \"{{count}} line(s) are still blank. Enter zero when the item is physically out of stock.\",\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.badgePosted\": \"Posted\",\n \"inventory.usageAudit.badgeApproved\": \"Approved\",\n \"inventory.usageAudit.batchNoStock\": \"{count} without stock — still queued\",\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.periodLabel\": \"Period\",\n \"inventory.usageAudit.period30\": \"30 days\",\n \"inventory.usageAudit.period90\": \"90 days\",\n \"inventory.usageAudit.periodAll\": \"All time\",\n \"inventory.usageAudit.filterPending\": \"Pending\",\n \"inventory.usageAudit.emptyPending\": \"No usage waiting for review in this period.\",\n \"inventory.usageAudit.columnActions\": \"Actions\",\n \"inventory.usageAudit.post\": \"Post\",\n \"inventory.usageAudit.approve\": \"Approve\",\n \"inventory.usageAudit.postHint\": \"Accepts the usage AND deducts stock\",\n \"inventory.usageAudit.approveHint\": \"Accepts the usage without touching stock\",\n \"inventory.usageAudit.posted\": \"{{count}} line(s) posted to stock\",\n \"inventory.usageAudit.approved\": \"{{count}} line(s) approved\",\n \"inventory.usageAudit.approveFailed\": \"Could not accept the usage\",\n \"inventory.usageAudit.noStock\": \"No stock to post — receive the product or use Approve\",\n \"inventory.usageAudit.filtersLabel\": \"Filters\",\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 \"inventory.recipes.edit\": \"Edit\",\n \"inventory.recipes.print\": \"Print recipe\",\n \"inventory.recipes.printNoSheet\": \"No recipe to print\",\n \"inventory.recipes.pickTitle\": \"Select product\",\n \"inventory.recipes.pickHint\": \"Choose the product this recipe belongs to.\",\n \"inventory.recipes.pickPlaceholder\": \"Search product...\",\n \"inventory.recipes.pickContinue\": \"Continue\",\n \"inventory.sheet.name\": \"Recipe name\",\n \"inventory.sheet.namePlaceholder\": \"E.g. Grilled picanha\",\n \"inventory.sheet.nameRequired\": \"The recipe name is required.\",\n \"inventory.sheet.yield\": \"Yield\",\n \"inventory.sheet.yieldUnit\": \"Yield unit\",\n \"inventory.sheet.none\": \"None\",\n \"inventory.sheet.yieldMode\": \"Yield type\",\n \"inventory.sheet.yieldMode.portion\": \"Portion (the recipe is 1 unit sold)\",\n \"inventory.sheet.yieldMode.batch\": \"Batch (the recipe produces the yield)\",\n \"inventory.sheet.yieldMode.portionHint\": \"The yield only describes the plate («serves 4», «6 pieces», «400 g»). The product cost is the recipe total.\",\n \"inventory.sheet.yieldMode.batchHint\": \"The recipe produces the yield (e.g. 2.4 kg of sauce). The product cost is the recipe total ÷ the yield, in the product's unit.\",\n \"inventory.sheet.prepTime\": \"Prep time (min)\",\n \"inventory.sheet.description\": \"Description\",\n \"inventory.sheet.descriptionPlaceholder\": \"General description of the recipe\",\n \"inventory.sheet.costPrice\": \"Cost price\",\n \"inventory.sheet.per\": \"per\",\n \"inventory.sheet.batchCost\": \"Batch\",\n \"inventory.sheet.salePrice\": \"Sale price\",\n \"inventory.sheet.cmv\": \"Food cost\",\n \"inventory.sheet.components\": \"Recipe components (by station)\",\n \"inventory.sheet.suggestAi\": \"Suggest with AI\",\n \"inventory.sheet.addGroup\": \"Add group\",\n \"inventory.sheet.noComponents\": \"No components yet. Click \\\"Add group\\\" or use \\\"Suggest with AI\\\".\",\n \"inventory.sheet.componentName\": \"Component name\",\n \"inventory.sheet.componentNamePlaceholder\": \"E.g. Fried strips\",\n \"inventory.sheet.station\": \"Production station\",\n \"inventory.sheet.stationPlaceholder\": \"Select the station\",\n \"inventory.sheet.noStations\": \"No stations registered\",\n \"inventory.sheet.estimatedMinutes\": \"Estimated time (min)\",\n \"inventory.sheet.estimatedMinutesPlaceholder\": \"E.g. 20\",\n \"inventory.sheet.componentMenu\": \"More component actions\",\n \"inventory.sheet.transform\": \"Turn into intermediate product\",\n \"inventory.sheet.deleteComponent\": \"Delete component\",\n \"inventory.sheet.transformNeedsLines\": \"Add at least one ingredient to this component.\",\n \"inventory.sheet.noLines\": \"No ingredients. Click \\\"Add item\\\".\",\n \"inventory.sheet.ingredient\": \"Ingredient\",\n \"inventory.sheet.quantity\": \"Quantity\",\n \"inventory.sheet.notes\": \"Notes\",\n \"inventory.sheet.cost\": \"Cost\",\n \"inventory.sheet.unit\": \"Unit\",\n \"inventory.sheet.searchIngredient\": \"Search ingredient...\",\n \"inventory.sheet.createIngredient\": \"Create ingredient\",\n \"inventory.sheet.ingredientCreated\": \"Ingredient \\\"{{name}}\\\" created\",\n \"inventory.sheet.ingredientCreateFailed\": \"Could not create the ingredient.\",\n \"inventory.sheet.aiHint\": \"Suggested by AI\",\n \"inventory.sheet.create\": \"Create\",\n \"inventory.sheet.updateCost\": \"Update cost\",\n \"inventory.sheet.updateCostCurrent\": \"Update cost (now: {{price}}{{unit}})\",\n \"inventory.sheet.setCost\": \"Set the ingredient's cost\",\n \"inventory.sheet.removeLine\": \"Remove ingredient\",\n \"inventory.sheet.addLine\": \"Add item\",\n \"inventory.sheet.componentPrep\": \"How to prepare this component\",\n \"inventory.sheet.componentPrepPlaceholder\": \"How this component is prepared at the station\",\n \"inventory.sheet.outputs\": \"Production outputs (optional)\",\n \"inventory.sheet.outputsHint\": \"When this recipe yields more than one product (e.g. fillet + trimmings + skin). With no lines, production delivers only the main product. The order cost is split by each output's %; left blank, by market value. Waste carries no cost.\",\n \"inventory.sheet.addOutput\": \"Add output\",\n \"inventory.sheet.product\": \"Product\",\n \"inventory.sheet.outputType\": \"Type\",\n \"inventory.sheet.expectedQty\": \"Expected qty\",\n \"inventory.sheet.costShare\": \"% of cost\",\n \"inventory.sheet.auto\": \"auto\",\n \"inventory.sheet.removeOutput\": \"Remove output\",\n \"inventory.sheet.outputType.main\": \"Main\",\n \"inventory.sheet.outputType.coproduct\": \"Co-product\",\n \"inventory.sheet.outputType.byproduct\": \"By-product\",\n \"inventory.sheet.outputType.waste\": \"Waste\",\n \"inventory.sheet.outputShareTitle\": \"Check the outputs' % of cost\",\n \"inventory.sheet.outputShareHint\": \"Fill the % on every usable output, adding up to 100% — or leave them all blank to split by market value.\",\n \"inventory.sheet.instructions\": \"Assembly instructions (optional)\",\n \"inventory.sheet.instructionsPlaceholder\": \"How to assemble and finish the dish once the components are ready...\",\n \"inventory.sheet.save\": \"Save recipe\",\n \"inventory.sheet.saving\": \"Saving...\",\n \"inventory.sheet.saved\": \"Recipe saved\",\n \"inventory.sheet.saveFailed\": \"Could not save.\",\n \"inventory.sheet.loadFailed\": \"Could not load the recipe.\",\n \"inventory.sheet.costDialogTitle\": \"Update cost\",\n \"inventory.sheet.costDialogHint\": \"Set it by hand or ask the AI for a market estimate.\",\n \"inventory.sheet.costAppliesEverywhere\": \"The cost applies to every recipe that uses this ingredient.\",\n \"inventory.sheet.costInvalid\": \"Enter a value above zero.\",\n \"inventory.sheet.costUpdated\": \"{{name}} now costs {{price}}\",\n \"inventory.sheet.aiNoPrice\": \"The AI returned no price.\",\n \"inventory.sheet.aiFailed\": \"The AI did not answer. Try again.\",\n \"inventory.sheet.aiUnitMismatch\": \"The AI priced it per {{ai}}; this ingredient is counted in {{unit}}. Check before saving.\",\n \"inventory.sheet.aiTitle\": \"Suggest recipe with AI\",\n \"inventory.sheet.aiPhotos\": \"Product photos\",\n \"inventory.sheet.aiPhotosHint\": \"The more angles of the dish, the better the suggestion.\",\n \"inventory.sheet.aiProductName\": \"Product name\",\n \"inventory.sheet.aiStations\": \"Stations available to the AI:\",\n \"inventory.sheet.aiNoStations\": \"No stations registered — add stations so the AI can group correctly.\",\n \"inventory.sheet.aiInstructions\": \"Extra instructions for the AI (optional)\",\n \"inventory.sheet.aiInstructionsPlaceholder\": \"E.g. serves 2, gluten-free, use clarified butter, keep the sauce at the cold station...\",\n \"inventory.sheet.aiReplaces\": \"The suggestion replaces the components on the recipe. Nothing is saved until you save.\",\n \"inventory.sheet.aiGenerate\": \"Generate suggestion\",\n \"inventory.sheet.aiGenerating\": \"Generating...\",\n \"inventory.sheet.aiApplied\": \"Suggestion applied — review and save.\",\n \"inventory.sheet.uploadFailed\": \"Could not upload the image.\",\n \"inventory.sheet.addPhoto\": \"Add photo\",\n \"inventory.sheet.removePhoto\": \"Remove photo\",\n \"inventory.sheet.transformHint\": \"A new intermediate product is created with this block as its recipe. The block leaves this recipe — you can then add the intermediate as an item anywhere.\",\n \"inventory.sheet.transformName\": \"Intermediate product name\",\n \"inventory.sheet.transformNamePlaceholder\": \"E.g. White rice portion\",\n \"inventory.sheet.transformUnitPlaceholder\": \"Select (g, kg, ml, L, un...)\",\n \"inventory.sheet.transformNameRequired\": \"Enter the intermediate product's name.\",\n \"inventory.sheet.transformYieldRequired\": \"Enter the yield.\",\n \"inventory.sheet.transformUnitRequired\": \"Select the yield unit.\",\n \"inventory.sheet.transformDuplicate\": \"A product with this name already exists.\",\n \"inventory.sheet.transformCreate\": \"Create intermediate\",\n \"inventory.sheet.transformCreating\": \"Creating...\",\n \"inventory.sheet.transformDone\": \"\\\"{{name}}\\\" was created. You can now add it as an item to any component of this recipe.\",\n \"inventory.sheet.transformFailed\": \"Could not create the intermediate.\",\n \"inventory.complements.tab\": \"Add-ons\",\n \"inventory.complements.title\": \"Add-ons and choices\",\n \"inventory.complements.hint\": \"Set up flavours, doneness and extras. Use 0.00 when a choice costs nothing extra.\",\n \"inventory.complements.newGroup\": \"New group\",\n \"inventory.complements.empty\": \"This product has no add-ons yet.\",\n \"inventory.complements.emptyHint\": \"Create a group to start, like “Doneness” or “Whipped cream”.\",\n \"inventory.complements.groupName\": \"Group name\",\n \"inventory.complements.groupNamePlaceholder\": \"E.g. Doneness\",\n \"inventory.complements.active\": \"Active\",\n \"inventory.complements.moveUp\": \"Move group up\",\n \"inventory.complements.moveDown\": \"Move group down\",\n \"inventory.complements.deleteGroup\": \"Delete group\",\n \"inventory.complements.required\": \"Required choice\",\n \"inventory.complements.min\": \"Minimum\",\n \"inventory.complements.max\": \"Maximum\",\n \"inventory.complements.option\": \"Option\",\n \"inventory.complements.price\": \"Extra charge\",\n \"inventory.complements.optionActive\": \"Active\",\n \"inventory.complements.optionPlaceholder\": \"E.g. With whipped cream\",\n \"inventory.complements.deleteOption\": \"Delete option\",\n \"inventory.complements.addOption\": \"Add option\",\n \"inventory.complements.save\": \"Save add-ons\",\n \"inventory.complements.saved\": \"Add-ons saved\",\n \"inventory.complements.saveFailed\": \"Could not save\",\n \"inventory.complements.review\": \"Review the add-ons\",\n \"inventory.complements.loadFailed\": \"Could not load the add-ons\",\n \"inventory.photoAi.title\": \"Generate photo with AI\",\n \"inventory.photoAi.product\": \"Product\",\n \"inventory.photoAi.category\": \"Category\",\n \"inventory.photoAi.usesSheet\": \"The recipe's ingredients go into the photo's description.\",\n \"inventory.photoAi.references\": \"Reference images (optional)\",\n \"inventory.photoAi.useCurrent\": \"Use the current photo as reference\",\n \"inventory.photoAi.add\": \"Add\",\n \"inventory.photoAi.instructionsPlaceholder\": \"E.g. wooden table, late-afternoon light, served on a white plate...\",\n \"inventory.photoAi.generate\": \"Generate photo\",\n \"inventory.photoAi.again\": \"Generate another\",\n \"inventory.photoAi.generating\": \"Generating the photo…\",\n \"inventory.photoAi.apply\": \"Apply photo\",\n \"inventory.photoAi.applied\": \"Photo applied to the product\",\n \"inventory.photoAi.failed\": \"Could not generate the photo\",\n \"inventory.sheet.quickTitle\": \"New ingredient\",\n \"inventory.sheet.quickHint\": \"Registers the product as an ingredient and puts it on this line.\",\n \"inventory.sheet.quickName\": \"Name\",\n \"inventory.sheet.quickUnit\": \"Stock unit\",\n \"inventory.sheet.quickUnitHint\": \"Base unit used in recipes, stock and sales (e.g. un, ml, g).\",\n \"inventory.sheet.quickNameRequired\": \"Enter the ingredient's name.\",\n \"inventory.sheet.quickUnitRequired\": \"Choose the unit the ingredient is counted in.\",\n \"inventory.sheet.quickCreate\": \"Create ingredient\",\n \"inventory.recipes.pickEmpty\": \"No sold or intermediate product found.\",\n \"inventory.recipes.kind.sale\": \"Sold\",\n \"inventory.recipes.kind.intermediate\": \"Intermediate\",\n \"inventory.recipes.kind.produced\": \"Produced\",\n \"inventory.recipes.kind.all\": \"All\",\n \"inventory.recipes.hasSheet\": \"Has recipe\",\n \"inventory.recipes.noSheetShort\": \"No recipe\",\n}\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"inventory.nav.panel\": \"Painel\",\n \"inventory.panel.columnProduct\": \"Produto\",\n \"inventory.panel.columnLocation\": \"Local\",\n \"inventory.panel.columnBatch\": \"Lote\",\n \"inventory.panel.columnExpiry\": \"Validade\",\n \"inventory.panel.columnQuantity\": \"Qtd / mín.\",\n \"inventory.panel.columnValue\": \"Valor\",\n \"inventory.panel.empty\": \"Nenhuma posição de estoque para este recorte.\",\n \"inventory.panel.totalLines\": \"Linhas\",\n \"inventory.panel.totalValue\": \"Valor em estoque\",\n \"inventory.panel.unsupported\": \"Este aplicativo não expõe o painel de estoque.\",\n \"inventory.filters.stockState\": \"Status do estoque\",\n \"inventory.filters.health.negative\": \"Negativo\",\n \"inventory.filters.health.below_min\": \"Abaixo do mín.\",\n \"inventory.filters.health.zero\": \"Zerado\",\n \"inventory.filters.health.ok\": \"OK\",\n \"inventory.filters.expiry\": \"Validade\",\n \"inventory.filters.expiry.all\": \"Todas\",\n \"inventory.filters.expiry.expired\": \"Vencidos\",\n \"inventory.filters.expiry.le30\": \"Vence em 30 dias\",\n \"inventory.filters.expiry.le60\": \"Vence em 60 dias\",\n \"inventory.filters.expiry.le90\": \"Vence em 90 dias\",\n \"inventory.filters.expiry.none\": \"Sem validade\",\n \"inventory.filters.batchPlaceholder\": \"Lote\",\n \"inventory.filters.productPlaceholder\": \"Buscar produto...\",\n \"inventory.filters.countState\": \"Situação da contagem\",\n \"inventory.filters.countAll\": \"Todas\",\n \"inventory.filters.countPending\": \"A contar\",\n \"inventory.filters.countDone\": \"Contadas\",\n \"inventory.filters.itemSearchPlaceholder\": \"Buscar produto ou código...\",\n \"inventory.filters.title\": \"Filtros\",\n \"inventory.filters.apply\": \"Buscar\",\n \"inventory.filters.pending\": \"Filtros alterados\",\n \"inventory.filters.pendingHint\": \"A lista ainda mostra o recorte anterior. Clique em Buscar para aplicar.\",\n \"inventory.filters.clear\": \"Limpar\",\n \"inventory.filters.more\": \"Mais filtros\",\n \"inventory.filters.less\": \"Menos filtros\",\n \"inventory.filters.from\": \"De\",\n \"inventory.filters.to\": \"Até\",\n \"inventory.filters.allTypes\": \"Todos os tipos\",\n \"inventory.filters.location\": \"Local\",\n \"inventory.filters.allLocations\": \"Todos os locais\",\n \"inventory.filters.category\": \"Categoria\",\n \"inventory.filters.allCategories\": \"Todas as categorias\",\n \"inventory.filters.kind\": \"Tipo de item\",\n \"inventory.filters.allKinds\": \"Todos\",\n \"inventory.filters.status\": \"Situação\",\n \"inventory.filters.allStatuses\": \"Todas\",\n \"inventory.stock.pendingRetry\": \"A confirmação ainda está pendente. Não faça outro lançamento. Tente novamente com os mesmos dados antes de sair desta tela.\",\n \"inventory.stock.refreshAfterCommit\": \"Movimento registrado. Atualize a tela para consultar o saldo.\",\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\": \"Fichas Técnicas\",\n \"inventory.entity.stockLocation\": \"Local de Estoque\",\n \"inventory.entity.stockLocation.plural\": \"Locais de Estoque\",\n \"inventory.entity.productCategory\": \"Categoria\",\n \"inventory.entity.productCategory.plural\": \"Categorias\",\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\": \"Resumo\",\n \"inventory.nav.entry\": \"Entrada\",\n \"inventory.nav.exit\": \"Saída\",\n \"inventory.nav.history\": \"Histórico\",\n \"inventory.nav.inventory\": \"Inventário\",\n \"inventory.nav.list\": \"Lista\",\n \"inventory.nav.new\": \"Novo\",\n \"inventory.nav.products\": \"Produtos\",\n \"inventory.nav.stock\": \"Movimentações\",\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 Ficha Técnica\",\n \"inventory.recipes.noRecipes\": \"Nenhum produto produzido ainda\",\n \"inventory.recipes.exporting\": \"Gerando a planilha das fichas…\",\n \"inventory.recipes.exported\": \"Planilha baixada\",\n \"inventory.sheet.print\": \"Imprimir\",\n \"inventory.sheet.printSaveFirst\": \"Salve a ficha antes de imprimir\",\n \"inventory.recipes.noCategory\": \"Sem categoria\",\n \"inventory.recipes.filterKind\": \"Tipo\",\n \"inventory.recipes.filterKindAll\": \"Todos os tipos\",\n \"inventory.recipes.kindSale\": \"Venda\",\n \"inventory.recipes.kindIntermediate\": \"Intermediário\",\n \"inventory.recipes.filterCategory\": \"Categoria\",\n \"inventory.recipes.filterCategoryAll\": \"Todas as categorias\",\n \"inventory.recipes.filterCmv\": \"CMV\",\n \"inventory.recipes.filterCmvAll\": \"Todo CMV\",\n \"inventory.recipes.cmvHigh\": \"CMV acima de {{pct}}%\",\n \"inventory.recipes.cmvGood\": \"CMV bom (abaixo de {{pct}}%)\",\n \"inventory.recipes.cmvAttention\": \"CMV atenção ({{from}}–{{to}}%)\",\n \"inventory.recipes.cmvNone\": \"Sem CMV\",\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\": \"Fichas Técnicas\",\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.minimum\": \"Mínimo\",\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.modules\": \"Módulos\",\n \"inventory.settings.modulesDesc\": \"O que desta casa aparece no Estoque\",\n \"inventory.settings.recipes\": \"Receitas\",\n \"inventory.settings.recipesDesc\": \"A ficha técnica que diz quanto cada produto consome\",\n \"inventory.settings.requisitions\": \"Requisições\",\n \"inventory.settings.requisitionsDesc\": \"Pedidos internos de material entre setores\",\n \"inventory.settings.usageAuditDesc\": \"O que saiu do estoque contra o que foi vendido\",\n \"inventory.settings.temperature\": \"Temperatura\",\n \"inventory.settings.temperatureDesc\": \"Registro de temperatura dos locais refrigerados\",\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 // As fichas do produto — portadas do cadastro do V1 (as abas por tipo).\n \"inventory.productForm.commissionPercent\": \"% Comissão (venda)\",\n \"inventory.productForm.commissionPercentHint\": \"Quanto o profissional ganha ao vender este produto.\",\n \"inventory.productForm.chartAccount\": \"Plano de Contas\",\n \"inventory.productForm.avgPurchasePrice\": \"Preço médio de compra\",\n \"inventory.productForm.avgPurchasePriceHint\": \"Atualizado a cada entrada de estoque.\",\n \"inventory.productForm.packaging\": \"Embalagem e Conversões\",\n \"inventory.productForm.packagingDesc\": \"Como a casa compra, quando é diferente de como ela conta.\",\n \"inventory.productForm.contentPerUnit\": \"Conteúdo por Unidade\",\n \"inventory.productForm.contentPerUnitHint\": \"Quanto cabe em UMA unidade de estoque (um frasco contém 300 ml).\",\n \"inventory.productForm.contentUnit\": \"Unidade de Conteúdo\",\n \"inventory.productForm.purchaseUnit\": \"Unidade de Compra\",\n \"inventory.productForm.conversionFactor\": \"Quantidade por Embalagem\",\n \"inventory.productForm.conversionFactorHint\": \"Quantas unidades de estoque vêm em uma unidade de compra.\",\n \"inventory.productForm.flagIngredient\": \"Insumo\",\n \"inventory.productForm.flagIngredientHint\": \"Aparece nas fichas técnicas.\",\n \"inventory.productForm.flagForSale\": \"Venda\",\n \"inventory.productForm.flagForSaleHint\": \"Cardápio, PDV, catálogo.\",\n \"inventory.productForm.flagIntermediate\": \"Intermediário\",\n \"inventory.productForm.flagIntermediateHint\": \"Produzido para consumir depois (molho, massa).\",\n \"inventory.productForm.flagAsset\": \"Patrimônio\",\n \"inventory.productForm.flagAssetHint\": \"Equipamento: entra no balanço, não se consome.\",\n \"inventory.productForm.flagProduced\": \"Produto produzido\",\n \"inventory.productForm.flagProducedHint\": \"Nasce de uma receita — habilita a ficha técnica.\",\n \"inventory.productForm.flagResale\": \"Revenda\",\n \"inventory.productForm.flagResaleHint\": \"Mercadoria destinada à revenda ao cliente.\",\n \"inventory.productForm.flagTracked\": \"Alto custo / etiquetado\",\n \"inventory.productForm.flagTrackedHint\": \"Cada unidade é acompanhada individualmente.\",\n \"inventory.productForm.professionalResalePrice\": \"Preço de revenda profissional\",\n \"inventory.productForm.professionalResalePriceHint\": \"Preço cobrado quando o profissional revende ao cliente final.\",\n \"inventory.productForm.requireBatch\": \"Exigir lote na entrada\",\n \"inventory.productForm.requireBatchHint\": \"Bloqueia entrada de estoque sem número de lote.\",\n \"inventory.productForm.requireExpiry\": \"Exigir validade na entrada\",\n \"inventory.productForm.requireExpiryHint\": \"Bloqueia entrada de estoque sem data de validade.\",\n \"inventory.productForm.notes\": \"Observações\",\n \"inventory.productForm.ingredientSection\": \"Insumo\",\n \"inventory.productForm.ingredientSectionDesc\": \"O que a compra precisa saber para repor na hora certa.\",\n \"inventory.productForm.ingReorderPoint\": \"Ponto de reposição\",\n \"inventory.productForm.ingReorderPointHint\": \"Fica ACIMA do mínimo: é o aviso que ainda chega a tempo de comprar.\",\n \"inventory.productForm.ingLeadTime\": \"Prazo de entrega (dias)\",\n \"inventory.productForm.ingShelfLife\": \"Validade (dias)\",\n \"inventory.productForm.ingStorageTemp\": \"Temperatura de armazenamento\",\n \"inventory.productForm.saleSection\": \"Venda\",\n \"inventory.productForm.saleSectionDesc\": \"O que o cardápio e o balcão mostram ao cliente.\",\n \"inventory.productForm.salePrepTime\": \"Tempo de preparo (min)\",\n \"inventory.productForm.saleServes\": \"Serve (pessoas)\",\n \"inventory.productForm.saleCalories\": \"Calorias (kcal)\",\n \"inventory.productForm.saleMenuDescription\": \"Descrição no cardápio\",\n \"inventory.productForm.saleAllergens\": \"Alergênicos\",\n \"inventory.productForm.saleAllergensPlaceholder\": \"Contém glúten, lactose\",\n \"inventory.productForm.saleSoldByWeight\": \"Vendido por peso\",\n \"inventory.productForm.saleHighlightDelivery\": \"Destacar no delivery\",\n \"inventory.productForm.saleAvailableDelivery\": \"Disponível no delivery\",\n \"inventory.productForm.saleAvailableCounter\": \"Disponível no balcão\",\n \"inventory.productForm.saleChannelsSection\": \"Preços por canal\",\n \"inventory.productForm.saleChannelsSectionDesc\": \"Deixe vazio o canal que usa o preço de venda base.\",\n \"inventory.productForm.intermediateSection\": \"Intermediário\",\n \"inventory.productForm.intermediateSectionDesc\": \"O que a produção precisa saber para preparar o lote.\",\n \"inventory.productForm.intYield\": \"Rendimento (%)\",\n \"inventory.productForm.intPrepTime\": \"Tempo de preparo (min)\",\n \"inventory.productForm.intShelfLifeHours\": \"Validade após preparo (h)\",\n \"inventory.productForm.intBatchSize\": \"Tamanho do lote\",\n \"inventory.productForm.intBatchUnit\": \"Unidade do lote\",\n \"inventory.productForm.intStorage\": \"Instruções de armazenamento\",\n \"inventory.productForm.assetSection\": \"Patrimônio\",\n \"inventory.productForm.assetSectionDesc\": \"O equipamento que a casa possui, e quem responde por ele.\",\n \"inventory.productForm.assetValue\": \"Valor do ativo\",\n \"inventory.productForm.assetResidualValue\": \"Valor residual\",\n \"inventory.productForm.assetUsefulLife\": \"Vida útil (meses)\",\n \"inventory.productForm.assetDepreciation\": \"Depreciação anual (%)\",\n \"inventory.productForm.assetSerial\": \"Número de série\",\n \"inventory.productForm.assetAcquisition\": \"Data de aquisição\",\n \"inventory.productForm.assetWarranty\": \"Garantia até\",\n \"inventory.productForm.assetStatus\": \"Situação\",\n \"inventory.productForm.assetLocation\": \"Localização\",\n \"inventory.productForm.assetLocationPlaceholder\": \"Sala 2, prateleira B\",\n \"inventory.productForm.assetResponsible\": \"Responsável\",\n \"inventory.productForm.assetInsurance\": \"Apólice de seguro\",\n \"inventory.productForm.assetLastMaintenance\": \"Última manutenção\",\n \"inventory.productForm.assetNextMaintenance\": \"Próxima manutenção\",\n \"inventory.productForm.taxSection\": \"Fiscal\",\n \"inventory.productForm.taxSectionDesc\": \"O que a nota precisa dizer sobre este produto. Em branco vale o que o grupo fiscal diz.\",\n \"inventory.productForm.taxGroup\": \"Grupo fiscal\",\n \"inventory.productForm.taxGroupHint\": \"Cadastre em Estoque › Notas Fiscais › Grupos Fiscais.\",\n \"inventory.productForm.ncmHint\": \"Classificação do produto na nota. É do produto, nunca do grupo.\",\n \"inventory.productForm.icmsOrigin\": \"ICMS de origem\",\n \"inventory.productForm.icmsRate\": \"Alíquota ICMS (%)\",\n \"inventory.productForm.cstHint\": \"CST tem 2 dígitos. CSOSN tem 3 e se configura no grupo fiscal, para o Simples Nacional.\",\n \"inventory.productForm.pisRate\": \"Alíquota PIS (%)\",\n \"inventory.productForm.cofinsRate\": \"Alíquota COFINS (%)\",\n \"inventory.productForm.baseCalcMode\": \"Modalidade de base de cálculo\",\n \"inventory.productForm.benefitCode\": \"Código de benefícios fiscais (cBenef)\",\n \"inventory.productForm.povertyFund\": \"Fundo de combate à pobreza (%)\",\n \"inventory.productForm.ibsCbsSituation\": \"IBS e CBS — situação tributária\",\n \"inventory.productForm.ibsCbsClassification\": \"IBS e CBS — classificação tributária\",\n \"inventory.productForm.classificationRequired\": \"Escolha ao menos uma classificação para o produto.\",\n \"inventory.productType.ingredient\": \"Insumo\",\n \"inventory.productType.sale\": \"Venda\",\n \"inventory.productType.intermediate\": \"Intermediário\",\n \"inventory.productType.asset\": \"Patrimônio\",\n \"inventory.variants.tab\": \"Variações\",\n \"inventory.variants.name\": \"Variação\",\n \"inventory.variants.namePlaceholder\": \"Ex.: M, G, GG, Azul\",\n \"inventory.variants.sku\": \"SKU\",\n \"inventory.variants.skuPlaceholder\": \"Opcional\",\n \"inventory.variants.default\": \"Padrão\",\n \"inventory.variants.empty\": \"Nenhuma variação. O produto é vendido e estocado como um item só.\",\n \"inventory.variants.duplicate\": \"Já existe uma variação com esse nome.\",\n \"inventory.variants.loadFailed\": \"Não foi possível carregar as variações.\",\n \"inventory.variants.saveFailed\": \"Não foi possível salvar a variação.\",\n \"inventory.variants.unavailable\": \"Variações não estão disponíveis nesta conta.\",\n \"inventory.variants.onHand\": \"{{count}} em estoque\",\n \"inventory.barcodes.tab\": \"Códigos de Barras\",\n \"inventory.barcodes.code\": \"Código de barras\",\n \"inventory.barcodes.codePlaceholder\": \"Digite ou bipe\",\n \"inventory.barcodes.type\": \"Tipo\",\n \"inventory.barcodes.description\": \"Descrição\",\n \"inventory.barcodes.descriptionPlaceholder\": \"Embalagem 500 ml\",\n \"inventory.barcodes.needCode\": \"Digite ou bipe um código.\",\n \"inventory.barcodes.empty\": \"Nenhum código de barras cadastrado.\",\n \"inventory.barcodes.duplicate\": \"Este código já está em uso.\",\n \"inventory.barcodes.isPrimary\": \"Principal — é o que a etiqueta imprime\",\n \"inventory.barcodes.makePrimary\": \"Tornar principal\",\n \"inventory.barcodes.removeTitle\": \"Remover este código de barras?\",\n \"inventory.barcodes.unavailable\": \"Códigos de barras indisponíveis neste ambiente.\",\n \"inventory.productRecipe.tab\": \"Ficha Técnica\",\n \"inventory.productRecipe.none\": \"Este produto ainda não tem ficha técnica.\",\n \"inventory.productRecipe.noneHint\": \"A ficha técnica diz de que o produto é feito — é dela que saem o custo e o CMV.\",\n \"inventory.productRecipe.goToRecipes\": \"Ir para Receitas\",\n \"inventory.productForm.classificationUnset\": \"Sem classificação\",\n \"inventory.productForm.stepIdentity\": \"Identificação\",\n \"inventory.productForm.stepClassification\": \"Classificação\",\n \"inventory.productForm.stepPricing\": \"Preço\",\n \"inventory.productForm.stepStock\": \"Estoque\",\n \"inventory.productForm.stepInitialEntry\": \"Entrada inicial\",\n \"inventory.productForm.initialEntrySection\": \"Dar entrada no estoque\",\n \"inventory.productForm.initialEntrySectionDesc\": \"Opcional: registre o que já está na prateleira. Deixe em branco para dar entrada depois.\",\n \"inventory.productForm.initialQuantity\": \"Quantidade em estoque\",\n \"inventory.productForm.initialLocation\": \"Local\",\n \"inventory.productForm.initialLocationHint\": \"Em branco usa o local padrão do produto.\",\n \"inventory.productForm.initialUnitCost\": \"Custo unitário\",\n \"inventory.productForm.initialUnitCostHint\": \"Em branco usa o custo do produto.\",\n \"inventory.productForm.initialBatch\": \"Lote\",\n \"inventory.productForm.initialExpiry\": \"Validade\",\n \"inventory.productForm.initialEntryFailed\": \"Produto criado, mas a entrada de estoque não foi registrada. Dê entrada pela aba Estoque.\",\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 receita...\",\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.\",\n \"inventory.counts.incomplete\": \"Finalize a contagem antes de fechar\",\n \"inventory.counts.incompleteDescription\": \"Ainda existem {{count}} linha(s) em branco. Informe zero quando o item acabou fisicamente.\",\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.badgePosted\": \"Baixado\",\n \"inventory.usageAudit.badgeApproved\": \"Aprovado\",\n \"inventory.usageAudit.batchNoStock\": \"{count} sem saldo — seguem na fila\",\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.periodLabel\": \"Período\",\n \"inventory.usageAudit.period30\": \"30 dias\",\n \"inventory.usageAudit.period90\": \"90 dias\",\n \"inventory.usageAudit.periodAll\": \"Todo o período\",\n \"inventory.usageAudit.filterPending\": \"Pendentes\",\n \"inventory.usageAudit.emptyPending\": \"Nenhum consumo esperando conferência neste período.\",\n \"inventory.usageAudit.columnActions\": \"Ações\",\n \"inventory.usageAudit.post\": \"Baixar\",\n \"inventory.usageAudit.approve\": \"Aprovar\",\n \"inventory.usageAudit.postHint\": \"Aceita o consumo E desconta do saldo\",\n \"inventory.usageAudit.approveHint\": \"Aceita o consumo sem mexer no saldo\",\n \"inventory.usageAudit.posted\": \"{{count}} linha(s) baixada(s) do estoque\",\n \"inventory.usageAudit.approved\": \"{{count}} linha(s) aprovada(s)\",\n \"inventory.usageAudit.approveFailed\": \"Não foi possível aceitar o consumo\",\n \"inventory.usageAudit.noStock\": \"Sem saldo para baixar — dê entrada no produto ou use Aprovar\",\n \"inventory.usageAudit.filtersLabel\": \"Filtros\",\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 \"inventory.recipes.edit\": \"Editar\",\n \"inventory.recipes.print\": \"Imprimir ficha técnica\",\n \"inventory.recipes.printNoSheet\": \"Sem ficha técnica para imprimir\",\n \"inventory.recipes.pickTitle\": \"Selecionar Produto\",\n \"inventory.recipes.pickHint\": \"Escolha o produto ao qual esta ficha técnica será associada.\",\n \"inventory.recipes.pickPlaceholder\": \"Buscar produto...\",\n \"inventory.recipes.pickContinue\": \"Continuar\",\n \"inventory.sheet.name\": \"Nome da Ficha Técnica\",\n \"inventory.sheet.namePlaceholder\": \"Ex: Picanha na Chapa\",\n \"inventory.sheet.nameRequired\": \"O nome da ficha técnica é obrigatório.\",\n \"inventory.sheet.yield\": \"Rendimento\",\n \"inventory.sheet.yieldUnit\": \"Unidade Rendimento\",\n \"inventory.sheet.none\": \"Nenhuma\",\n \"inventory.sheet.yieldMode\": \"Tipo de rendimento\",\n \"inventory.sheet.yieldMode.portion\": \"Porção (a ficha é 1 unidade vendida)\",\n \"inventory.sheet.yieldMode.batch\": \"Lote (a ficha produz o rendimento)\",\n \"inventory.sheet.yieldMode.portionHint\": \"O rendimento só descreve o que vai no prato («para 4 pessoas», «6 unidades», «400 g»). O custo do produto é a soma da ficha.\",\n \"inventory.sheet.yieldMode.batchHint\": \"A ficha produz o rendimento informado (ex.: 2,4 kg de molho). O custo do produto é a soma da ficha ÷ o rendimento, na unidade do produto.\",\n \"inventory.sheet.prepTime\": \"Tempo Preparo (min)\",\n \"inventory.sheet.description\": \"Descrição Geral\",\n \"inventory.sheet.descriptionPlaceholder\": \"Descrição geral da ficha técnica\",\n \"inventory.sheet.costPrice\": \"Preço de Custo\",\n \"inventory.sheet.per\": \"por\",\n \"inventory.sheet.batchCost\": \"Lote\",\n \"inventory.sheet.salePrice\": \"Preço de Venda\",\n \"inventory.sheet.cmv\": \"CMV\",\n \"inventory.sheet.components\": \"Componentes da Ficha Técnica (por estação)\",\n \"inventory.sheet.suggestAi\": \"Sugerir com IA\",\n \"inventory.sheet.addGroup\": \"Adicionar Grupo\",\n \"inventory.sheet.noComponents\": \"Nenhum componente adicionado. Clique em \\\"Adicionar Grupo\\\" ou use \\\"Sugerir com IA\\\".\",\n \"inventory.sheet.componentName\": \"Nome do Componente\",\n \"inventory.sheet.componentNamePlaceholder\": \"Ex: Porção de Iscas\",\n \"inventory.sheet.station\": \"Estação de Produção\",\n \"inventory.sheet.stationPlaceholder\": \"Selecione a estação\",\n \"inventory.sheet.noStations\": \"Nenhuma estação cadastrada\",\n \"inventory.sheet.estimatedMinutes\": \"Tempo estimado (min)\",\n \"inventory.sheet.estimatedMinutesPlaceholder\": \"Ex: 20\",\n \"inventory.sheet.componentMenu\": \"Mais ações do componente\",\n \"inventory.sheet.transform\": \"Transformar em produto intermediário\",\n \"inventory.sheet.deleteComponent\": \"Excluir componente\",\n \"inventory.sheet.transformNeedsLines\": \"Adicione ao menos um insumo neste componente.\",\n \"inventory.sheet.noLines\": \"Nenhum insumo. Clique em \\\"Adicionar Item\\\".\",\n \"inventory.sheet.ingredient\": \"Insumo\",\n \"inventory.sheet.quantity\": \"Quantidade\",\n \"inventory.sheet.notes\": \"Obs\",\n \"inventory.sheet.cost\": \"Custo\",\n \"inventory.sheet.unit\": \"Unidade\",\n \"inventory.sheet.searchIngredient\": \"Buscar insumo...\",\n \"inventory.sheet.createIngredient\": \"Criar insumo\",\n \"inventory.sheet.ingredientCreated\": \"Insumo \\\"{{name}}\\\" criado\",\n \"inventory.sheet.ingredientCreateFailed\": \"Não foi possível criar o insumo.\",\n \"inventory.sheet.aiHint\": \"Sugerido pela IA\",\n \"inventory.sheet.create\": \"Criar\",\n \"inventory.sheet.updateCost\": \"Atualizar custo\",\n \"inventory.sheet.updateCostCurrent\": \"Atualizar custo (atual: {{price}}{{unit}})\",\n \"inventory.sheet.setCost\": \"Definir preço de custo do insumo\",\n \"inventory.sheet.removeLine\": \"Remover insumo\",\n \"inventory.sheet.addLine\": \"Adicionar Item\",\n \"inventory.sheet.componentPrep\": \"Modo de Preparo deste Componente\",\n \"inventory.sheet.componentPrepPlaceholder\": \"Como preparar este componente na estação\",\n \"inventory.sheet.outputs\": \"Saídas da produção (opcional)\",\n \"inventory.sheet.outputsHint\": \"Quando esta ficha gera mais de um produto (ex.: filé + aparas + pele). Sem linhas aqui, a produção entrega apenas o produto principal com o rendimento da ficha. O custo da OP é dividido pelo % de cada saída; em branco, pelo valor de mercado (preço médio de compra × quantidade). Rejeito não leva custo.\",\n \"inventory.sheet.addOutput\": \"Adicionar saída\",\n \"inventory.sheet.product\": \"Produto\",\n \"inventory.sheet.outputType\": \"Tipo\",\n \"inventory.sheet.expectedQty\": \"Qtd esperada\",\n \"inventory.sheet.costShare\": \"% do custo\",\n \"inventory.sheet.auto\": \"auto\",\n \"inventory.sheet.removeOutput\": \"Remover saída\",\n \"inventory.sheet.outputType.main\": \"Principal\",\n \"inventory.sheet.outputType.coproduct\": \"Coproduto\",\n \"inventory.sheet.outputType.byproduct\": \"Subproduto\",\n \"inventory.sheet.outputType.waste\": \"Descarte\",\n \"inventory.sheet.outputShareTitle\": \"Confira o % do custo das saídas\",\n \"inventory.sheet.outputShareHint\": \"Preencha o % em todas as saídas aproveitáveis, somando 100% — ou deixe todas em branco para ratear pelo valor de mercado.\",\n \"inventory.sheet.instructions\": \"Modo de Preparo Geral / Montagem (opcional)\",\n \"inventory.sheet.instructionsPlaceholder\": \"Como montar e finalizar o prato após os componentes prontos...\",\n \"inventory.sheet.save\": \"Salvar Ficha Técnica\",\n \"inventory.sheet.saving\": \"Salvando...\",\n \"inventory.sheet.saved\": \"Ficha técnica salva\",\n \"inventory.sheet.saveFailed\": \"Não foi possível salvar.\",\n \"inventory.sheet.loadFailed\": \"Não foi possível carregar a ficha técnica.\",\n \"inventory.sheet.costDialogTitle\": \"Atualizar custo\",\n \"inventory.sheet.costDialogHint\": \"Defina manualmente ou peça uma sugestão à IA com base no mercado.\",\n \"inventory.sheet.costAppliesEverywhere\": \"O custo vale para todas as fichas que usam este insumo.\",\n \"inventory.sheet.costInvalid\": \"Informe um valor maior que zero.\",\n \"inventory.sheet.costUpdated\": \"{{name}} agora custa {{price}}\",\n \"inventory.sheet.aiNoPrice\": \"A IA não retornou um preço.\",\n \"inventory.sheet.aiFailed\": \"A IA não respondeu. Tente novamente.\",\n \"inventory.sheet.aiUnitMismatch\": \"A IA deu o preço por {{ai}}; este insumo é contado em {{unit}}. Confira antes de salvar.\",\n \"inventory.sheet.aiTitle\": \"Sugerir Ficha Técnica com IA\",\n \"inventory.sheet.aiPhotos\": \"Fotos do produto\",\n \"inventory.sheet.aiPhotosHint\": \"Quanto mais ângulos do prato, melhor a sugestão.\",\n \"inventory.sheet.aiProductName\": \"Nome do produto\",\n \"inventory.sheet.aiStations\": \"Estações disponíveis para a IA:\",\n \"inventory.sheet.aiNoStations\": \"Nenhuma estação cadastrada — cadastre estações para a IA agrupar corretamente.\",\n \"inventory.sheet.aiInstructions\": \"Instruções adicionais para a IA (opcional)\",\n \"inventory.sheet.aiInstructionsPlaceholder\": \"Ex.: Porção para 2 pessoas, sem glúten, usar manteiga clarificada, separar molho em estação fria...\",\n \"inventory.sheet.aiReplaces\": \"A sugestão substitui os componentes que estão na ficha. Nada é gravado até você salvar.\",\n \"inventory.sheet.aiGenerate\": \"Gerar sugestão\",\n \"inventory.sheet.aiGenerating\": \"Gerando...\",\n \"inventory.sheet.aiApplied\": \"Sugestão aplicada — confira e salve.\",\n \"inventory.sheet.uploadFailed\": \"Não foi possível enviar a imagem.\",\n \"inventory.sheet.addPhoto\": \"Adicionar foto\",\n \"inventory.sheet.removePhoto\": \"Remover foto\",\n \"inventory.sheet.transformHint\": \"Será criado um novo produto do tipo intermediário com esta ficha técnica (ingredientes e modo de preparo). O bloco atual será removido daqui — depois você pode adicionar este intermediário em qualquer etapa.\",\n \"inventory.sheet.transformName\": \"Nome do Produto Intermediário\",\n \"inventory.sheet.transformNamePlaceholder\": \"Ex: Arroz Branco Porção\",\n \"inventory.sheet.transformUnitPlaceholder\": \"Selecione (g, kg, ml, L, un...)\",\n \"inventory.sheet.transformNameRequired\": \"Informe o nome do produto intermediário.\",\n \"inventory.sheet.transformYieldRequired\": \"Informe o rendimento.\",\n \"inventory.sheet.transformUnitRequired\": \"Selecione a unidade de medida do rendimento.\",\n \"inventory.sheet.transformDuplicate\": \"Já existe um produto com este nome.\",\n \"inventory.sheet.transformCreate\": \"Criar Intermediário\",\n \"inventory.sheet.transformCreating\": \"Criando...\",\n \"inventory.sheet.transformDone\": \"\\\"{{name}}\\\" foi cadastrado. Agora você pode adicioná-lo como item em qualquer componente desta ficha técnica.\",\n \"inventory.sheet.transformFailed\": \"Falha ao transformar em intermediário.\",\n \"inventory.complements.tab\": \"Complementos\",\n \"inventory.complements.title\": \"Complementos e escolhas\",\n \"inventory.complements.hint\": \"Configure sabores, pontos de preparo e adicionais. Use R$ 0,00 quando a escolha não tiver acréscimo.\",\n \"inventory.complements.newGroup\": \"Novo grupo\",\n \"inventory.complements.empty\": \"Este produto ainda não possui complementos.\",\n \"inventory.complements.emptyHint\": \"Crie um grupo para começar, como “Ponto da carne” ou “Chantilly”.\",\n \"inventory.complements.groupName\": \"Nome do grupo\",\n \"inventory.complements.groupNamePlaceholder\": \"Ex: Ponto da carne\",\n \"inventory.complements.active\": \"Ativo\",\n \"inventory.complements.moveUp\": \"Mover grupo para cima\",\n \"inventory.complements.moveDown\": \"Mover grupo para baixo\",\n \"inventory.complements.deleteGroup\": \"Excluir grupo\",\n \"inventory.complements.required\": \"Escolha obrigatória\",\n \"inventory.complements.min\": \"Mínimo\",\n \"inventory.complements.max\": \"Máximo\",\n \"inventory.complements.option\": \"Opção\",\n \"inventory.complements.price\": \"Acréscimo\",\n \"inventory.complements.optionActive\": \"Ativa\",\n \"inventory.complements.optionPlaceholder\": \"Ex: Com chantilly\",\n \"inventory.complements.deleteOption\": \"Excluir opção\",\n \"inventory.complements.addOption\": \"Adicionar opção\",\n \"inventory.complements.save\": \"Salvar complementos\",\n \"inventory.complements.saved\": \"Complementos salvos\",\n \"inventory.complements.saveFailed\": \"Não foi possível salvar\",\n \"inventory.complements.review\": \"Revise os complementos\",\n \"inventory.complements.loadFailed\": \"Não foi possível carregar os complementos\",\n \"inventory.photoAi.title\": \"Gerar foto com IA\",\n \"inventory.photoAi.product\": \"Produto\",\n \"inventory.photoAi.category\": \"Categoria\",\n \"inventory.photoAi.usesSheet\": \"Os insumos da ficha técnica entram na descrição da foto.\",\n \"inventory.photoAi.references\": \"Imagens de referência (opcional)\",\n \"inventory.photoAi.useCurrent\": \"Usar foto atual do produto como referência\",\n \"inventory.photoAi.add\": \"Adicionar\",\n \"inventory.photoAi.instructionsPlaceholder\": \"Ex.: fundo de madeira, luz de fim de tarde, porção servida em prato branco...\",\n \"inventory.photoAi.generate\": \"Gerar foto\",\n \"inventory.photoAi.again\": \"Gerar outra\",\n \"inventory.photoAi.generating\": \"Gerando a foto…\",\n \"inventory.photoAi.apply\": \"Aplicar foto\",\n \"inventory.photoAi.applied\": \"Foto aplicada ao produto\",\n \"inventory.photoAi.failed\": \"Não foi possível gerar a foto\",\n \"inventory.sheet.quickTitle\": \"Novo insumo\",\n \"inventory.sheet.quickHint\": \"Cadastra o produto como Insumo e o coloca nesta linha.\",\n \"inventory.sheet.quickName\": \"Nome\",\n \"inventory.sheet.quickUnit\": \"Unidade de Estoque\",\n \"inventory.sheet.quickUnitHint\": \"Unidade base usada em ficha técnica, estoque e vendas (ex: un, ml, g).\",\n \"inventory.sheet.quickNameRequired\": \"Informe o nome do insumo.\",\n \"inventory.sheet.quickUnitRequired\": \"Escolha a unidade em que o insumo é contado.\",\n \"inventory.sheet.quickCreate\": \"Criar insumo\",\n \"inventory.recipes.pickEmpty\": \"Nenhum produto de venda ou intermediário encontrado.\",\n \"inventory.recipes.kind.sale\": \"Venda\",\n \"inventory.recipes.kind.intermediate\": \"Intermediário\",\n \"inventory.recipes.kind.produced\": \"Produzido\",\n \"inventory.recipes.kind.all\": \"Todos\",\n \"inventory.recipes.hasSheet\": \"Com ficha\",\n \"inventory.recipes.noSheetShort\": \"Sem ficha\",\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, 003_stock_count_closes_through_ledger.sql, 004_a_posicao_de_estoque_atravessa.sql, 005_a_posicao_e_consequencia_do_movimento.sql, 006_a_producao_tem_ordem_e_estacao.sql, 007_a_producao_atravessa.sql, 008_o_grupo_da_receita_tambem_e_de_uma_casa.sql, 009_a_direcao_do_movimento_nao_esta_no_numero.sql, 010_a_entrada_de_notas_atravessa.sql, 011_o_consumo_tem_duas_origens.sql, 012_o_consumo_clinico_nao_precisa_da_tabela_de_itens_inteira.sql, 013_a_fila_de_auditoria_tem_uma_janela.sql, 014_a_sessao_se_busca_uma_a_uma.sql, 015_lateral_sem_cerca_nao_e_lateral.sql, 016_a_data_do_consumo_e_uma_coluna.sql, 017_aprovar_e_baixar_sao_dois_gestos.sql, 018_o_nome_nao_sai_da_vista.sql, 019_sem_saldo_nao_se_baixa.sql, 020_o_produto_e_varias_coisas_ao_mesmo_tempo.sql, 021_o_razao_diz_de_onde_veio.sql, 022_receber_estoque_volta_a_funcionar.sql, 023_a_receita_se_escreve_com_permissao.sql, 024_a_categoria_do_produto_e_do_catalogo.sql, 025_a_ficha_tecnica_por_estacao.sql, 026_stock_cost_knows_its_currency.sql, 027_a_receipt_names_the_line_it_came_from.sql, 028_a_receipt_keeps_the_variant.sql, 029_a_reversal_undoes_the_same_variant.sql, 030_the_minimum_can_be_saved.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 MIGRATION_003_STOCK_COUNT_CLOSES_THROUGH_LEDGER = `-- 003_stock_count_closes_through_ledger.sql\n--\n-- A physical count is a reconciliation, not a second stock writer. The old\n-- function inserted values into GENERATED columns, recorded the counted total\n-- instead of the variance and then updated the position a second time outside\n-- the ledger trigger. This replacement emits one canonical \\`adjust\\` movement\n-- per divergent line and lets the existing movement trigger update the balance.\n--\n-- Safety gates: every line must be counted (zero is valid); any stock movement\n-- after the opening snapshot aborts the close; lot stock requires a future\n-- batch-aware count instead of guessing which lot changed.\n\nCREATE OR REPLACE 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 ''\n AS $$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_session public.plg_inventory_count_sessions%ROWTYPE;\n v_item public.plg_inventory_count_items%ROWTYPE;\n v_op record;\n v_delta numeric;\n v_current numeric;\n v_current_cost numeric;\n v_has_lots boolean;\n v_movement_id uuid;\n v_reason text;\n v_key text := 'count:' || p_session_id::text || ':close:v1';\n v_line_no int := 0;\n v_uncounted int;\n v_conflicts int;\n v_emitted int := 0;\n v_movements jsonb := '[]'::jsonb;\n v_positions jsonb := '[]'::jsonb;\n v_result jsonb;\nBEGIN\n SELECT * INTO v_session FROM public.plg_inventory_count_sessions\n WHERE id = p_session_id AND tenant_id = v_tenant FOR UPDATE;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('ok', false, 'error', 'unknown count session');\n END IF;\n PERFORM app.inventory_authorize_location(v_tenant, v_session.stock_location_id, 'inventory.edit');\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 SELECT count(*) INTO v_uncounted\n FROM public.plg_inventory_count_items i\n WHERE i.session_id = p_session_id AND i.counted_quantity IS NULL;\n IF v_uncounted > 0 THEN\n RAISE EXCEPTION 'inventory: count session has % uncounted line(s)', v_uncounted\n USING ERRCODE = '22023', HINT = 'Count every line, including physical zero, before closing.';\n END IF;\n\n PERFORM p.id\n FROM public.plg_inventory_stock_positions p\n JOIN public.plg_inventory_count_items i\n ON i.tenant_id = p.tenant_id AND i.product_id = p.product_id\n WHERE i.session_id = p_session_id\n AND p.stock_location_id = v_session.stock_location_id\n ORDER BY p.id\n FOR UPDATE OF p;\n\n SELECT count(DISTINCT i.id) INTO v_conflicts\n FROM public.plg_inventory_count_items i\n JOIN public.plg_inventory_stock_movements m\n ON m.tenant_id = i.tenant_id\n AND m.product_id = i.product_id\n AND (m.source_location_id = v_session.stock_location_id\n OR m.destination_location_id = v_session.stock_location_id)\n WHERE i.session_id = p_session_id\n AND m.created_at > v_session.opened_at\n AND (i.movement_id IS NULL OR m.id <> i.movement_id);\n IF v_conflicts > 0 THEN\n RAISE EXCEPTION 'inventory: stock changed after this count opened (% line(s)); review and recount', v_conflicts\n USING ERRCODE = '40001';\n END IF;\n\n SELECT * INTO v_op FROM app.inventory_begin_operation(\n v_tenant, 'adjust', v_key,\n jsonb_build_object('count_session_id', p_session_id, 'reason', v_reason));\n IF v_op.existing IS NOT NULL THEN\n UPDATE public.plg_inventory_count_sessions\n SET status = 'closed', closed_at = coalesce(closed_at, now()),\n closed_by = coalesce(closed_by, auth.uid()), updated_at = now()\n WHERE id = p_session_id;\n RETURN v_op.existing || jsonb_build_object('already_closed', true, 'adjustments_created', 0);\n END IF;\n\n FOR v_item IN\n SELECT * FROM public.plg_inventory_count_items\n WHERE session_id = p_session_id AND movement_id IS NULL\n ORDER BY id\n FOR UPDATE\n LOOP\n SELECT coalesce(sum(p.quantity), 0),\n coalesce(max(p.unit_cost), v_item.unit_cost, 0),\n coalesce(bool_or((p.batch_number IS NOT NULL OR p.expiration_date IS NOT NULL) AND p.quantity <> 0), false)\n INTO v_current, v_current_cost, v_has_lots\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant\n AND p.product_id = v_item.product_id\n AND p.stock_location_id = v_session.stock_location_id;\n\n v_delta := v_item.counted_quantity - v_current;\n IF v_delta = 0 THEN CONTINUE; END IF;\n IF v_has_lots THEN\n RAISE EXCEPTION 'inventory: product % has batch stock; close it with a batch-aware count', v_item.product_id\n USING ERRCODE = '22023';\n END IF;\n\n v_line_no := v_line_no + 1;\n INSERT INTO public.plg_inventory_stock_movements (\n tenant_id, product_id, kind, quantity, unit_cost,\n source_location_id, document_type, reason,\n idempotency_key, line_no, operation_id,\n source_item_type, source_item_id, metadata\n ) VALUES (\n v_tenant, v_item.product_id, 'adjust', v_delta, v_current_cost,\n v_session.stock_location_id, 'stock_count', v_reason,\n v_key, v_line_no, v_op.op_id,\n 'stock_count_item', v_item.id,\n jsonb_build_object(\n 'countSessionId', p_session_id,\n 'countItemId', v_item.id,\n 'systemQuantity', v_item.system_quantity,\n 'currentQuantity', v_current,\n 'countedQuantity', v_item.counted_quantity,\n 'variance', v_delta\n )\n )\n RETURNING id INTO v_movement_id;\n\n UPDATE public.plg_inventory_count_items\n SET movement_id = v_movement_id, updated_at = now()\n WHERE id = v_item.id;\n v_movements := v_movements || app.inventory_movement_json(v_movement_id);\n v_positions := v_positions || app.inventory_position_json(\n v_tenant, v_item.product_id, v_session.stock_location_id, NULL, NULL);\n v_emitted := v_emitted + 1;\n END LOOP;\n\n UPDATE public.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 v_result := jsonb_build_object(\n 'ok', true, 'session_id', p_session_id, 'status', 'closed',\n 'already_closed', false, 'adjustments_created', v_emitted,\n 'operation_id', v_op.op_id, 'idempotency_key', v_key,\n 'movements', v_movements, 'positions', v_positions);\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, 'count.close', v_key, v_result,\n jsonb_build_object('count_session_id', p_session_id, 'adjustments_created', v_emitted));\nEND;\n$$;\n`\n\nexport const MIGRATION_004_A_POSICAO_DE_ESTOQUE_ATRAVESSA = `-- A posição de estoque atravessa.\n--\n-- \\`stock_positions\\` — o saldo por produto × local × lote — estava no plano de\n-- leitura e sem destino: 1.861 linhas do tenant Pertinho do Céu ficaram\n-- \\`pendentes\\` em toda rodada, nunca ofertadas a writer nenhum. A nota no\n-- extrator dizia \"no V2 a posição é derivada do movimento\", e essa frase é\n-- verdadeira e insuficiente.\n--\n-- Derivar o saldo do movimento só dá o mesmo número quando o movimento\n-- atravessa INTEIRO. Neste tenant 2.208 dos 2.697 movimentos estavam em\n-- quarentena, então o saldo derivado seria o saldo de 18% do histórico —\n-- apresentado com a mesma confiança do saldo certo. E lote e validade, que a\n-- posição carrega e o movimento não, não se derivam de soma nenhuma.\n--\n-- Então a posição vem do V1 como fato, e não como conta.\n--\n-- ── O que o destino exige e a origem não dá ─────────────────────────────────\n--\n-- \\`plg_inventory_stock_positions\\` tem três colunas NOT NULL que precisam de\n-- tradução:\n--\n-- product_id → resolvido pelo ledger de \\`products\\`\n-- stock_location_id → pelo ledger de \\`stock_locations\\`\n-- unit_id → a unidade da EMPRESA (app.units), e o V1 guarda duas\n-- coisas com nome parecido: \\`unit_id\\` (a unidade de\n-- MEDIDA do item) e \\`company_unit_id\\` (a filial). É a\n-- segunda. Confundi-las poria a posição na unidade\n-- errada — e num tenant de 63 filiais isso é saldo no\n-- lugar de outro.\n--\n-- Quando a filial não vem na linha, ela vem do LOCAL: um local de estoque\n-- pertence a uma unidade, e o saldo que está nele está nela.\n--\n-- Idempotente.\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 1. O writer\n-- ─────────────────────────────────────────────────────────────────────────────\n\nCREATE OR REPLACE FUNCTION migration.upsert_inv_position(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_product uuid := (p_row ->> 'product_id')::uuid;\n v_location uuid := (p_row ->> 'stock_location_id')::uuid;\n v_unit uuid := (p_row ->> 'unit_id')::uuid;\n v_qty numeric := round(coalesce((p_row ->> 'quantity')::numeric, 0), 4);\n v_existing_tenant uuid;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state', 'reason', 'uma posição precisa de id');\n END IF;\n IF v_product IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', 'posição de saldo cujo produto ainda não atravessou');\n END IF;\n IF v_location IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', 'posição de saldo sem local — saldo sem lugar não é saldo');\n END IF;\n\n -- A filial pelo LOCAL quando a linha não a traz: o local pertence a uma\n -- unidade, e o saldo que está nele está nela.\n IF v_unit IS NULL THEN\n SELECT l.unit_id INTO v_unit\n FROM public.plg_inventory_stock_locations l\n WHERE l.id = v_location AND l.tenant_id = p_tenant;\n END IF;\n IF v_unit IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', 'posição sem unidade, e o local dela também não diz de qual é');\n END IF;\n\n -- \\`quantity >= 0\\` é CHECK da tabela. O V1 admite saldo negativo (saída que\n -- não conferiu com a entrada); recusar aqui, com a frase, é melhor que o erro\n -- cru do banco no meio do lote — e melhor que gravar zero, que apagaria a\n -- evidência de que a contagem daquele item está furada.\n IF v_qty < 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('saldo negativo (%s) — o V1 admite, o razão de estoque do V2 não', v_qty));\n END IF;\n\n SELECT tenant_id INTO v_existing_tenant FROM public.plg_inventory_stock_positions WHERE id = p_id;\n IF v_existing_tenant IS NOT NULL AND v_existing_tenant <> p_tenant THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'tenant',\n 'reason', format('%s already exists in another tenant', p_id));\n END IF;\n\n IF v_existing_tenant IS NULL THEN\n INSERT INTO public.plg_inventory_stock_positions\n (id, tenant_id, unit_id, product_id, stock_location_id, quantity, unit_cost,\n batch_number, expiration_date, unit_type)\n VALUES (p_id, p_tenant, v_unit, v_product, v_location, v_qty,\n round(coalesce((p_row ->> 'unit_cost')::numeric, 0), 4),\n p_row ->> 'batch_number', (p_row ->> 'expiration_date')::date,\n coalesce(nullif(btrim(p_row ->> 'unit_type'), ''), 'base'));\n v_created := true;\n ELSE\n UPDATE public.plg_inventory_stock_positions SET\n unit_id = coalesce(v_unit, unit_id),\n product_id = coalesce(v_product, product_id),\n stock_location_id = coalesce(v_location, stock_location_id),\n quantity = CASE WHEN p_row ? 'quantity' THEN v_qty ELSE quantity END,\n unit_cost = CASE WHEN p_row ? 'unit_cost' THEN round(coalesce((p_row ->> 'unit_cost')::numeric, 0), 4) ELSE unit_cost END,\n batch_number = CASE WHEN p_row ? 'batch_number' THEN p_row ->> 'batch_number' ELSE batch_number END,\n expiration_date = CASE WHEN p_row ? 'expiration_date' THEN (p_row ->> 'expiration_date')::date ELSE expiration_date END,\n unit_type = CASE WHEN p_row ? 'unit_type' THEN coalesce(nullif(btrim(p_row ->> 'unit_type'), ''), 'base') ELSE unit_type END,\n updated_at = now()\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_inventory_stock_positions', p_id, jsonb_build_object('reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END)); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 2. O vocabulário de writers aceita o nome novo\n-- ─────────────────────────────────────────────────────────────────────────────\n\nDO $$\nDECLARE v_def text;\nBEGIN\n SELECT pg_get_constraintdef(oid) INTO v_def\n FROM pg_constraint WHERE conname = 'allowlist_writer_check';\n IF v_def IS NULL OR strpos(v_def, 'inv_position') > 0 THEN RETURN; END IF;\n ALTER TABLE migration.allowlist DROP CONSTRAINT allowlist_writer_check;\n EXECUTE replace(\n 'ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check ' || v_def,\n '''inv_movement''::text',\n '''inv_movement''::text, ''inv_position''::text');\nEND $$;\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 3. O de-para\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- \\`unit_id\\` do V1 é a unidade de MEDIDA e não a filial — por isso ela vai para\n-- metadata e quem responde pela filial é \\`company_unit_id\\`.\n\n-- A allowlist é CONGELADA (\\`trg_allowlist_frozen\\`): mudança de core-A é\n-- arquivo de migration, não escrita solta — e esta é um arquivo. A escotilha\n-- é transacional (\\`true\\` no terceiro argumento), então não fica porta aberta.\nSELECT set_config('migration.allowlist_unlock', 'on', true);\n\nSELECT migration._allow(\n 'stock_positions', 'public.plg_inventory_stock_positions', 'inventory',\n 'inv_position', '{}'::jsonb, ARRAY['quantity', 'unit_cost'],\n jsonb_build_object(\n 'uuid', 'id',\n 'product_id', 'product_id@products',\n 'stock_location_id', 'stock_location_id@stock_locations',\n 'company_unit_id', 'unit_id@companies:app.units',\n 'quantity', 'quantity',\n 'unit_cost', 'unit_cost',\n 'batch_number', 'batch_number',\n 'expiration_date', 'expiration_date',\n 'unit_type', 'unit_type',\n 'location', 'jsonb:v1.location_label',\n 'unit_id', 'jsonb:v1.measurement_unit_ref'\n ),\n 'O SALDO por produto × local × lote. Vem da origem como FATO e não derivado '\n 'do movimento: o saldo derivado só bate quando o movimento atravessa inteiro, '\n 'e lote e validade a posição carrega e o movimento não.'\n);\n\nSELECT set_config('migration.allowlist_unlock', 'off', true);\n\n\n-- ── quem pode executar ────────────────────────────────────────────────────\n--\n-- Função nova nasce executável por PUBLIC, e \\`anon\\`/\\`authenticated\\` herdam\n-- dali. Estas são de PORTE: SECURITY DEFINER, escrevem dados de qualquer\n-- inquilino, e uma delas alcançável pela chave anônima é a base inteira\n-- alcançável pela chave anônima. Só o service_role, que é quem roda a onda.\nREVOKE ALL ON FUNCTION migration.upsert_inv_position(uuid, uuid, jsonb, jsonb) FROM PUBLIC, anon, authenticated;\nGRANT EXECUTE ON FUNCTION migration.upsert_inv_position(uuid, uuid, jsonb, jsonb) TO service_role;\n`\n\nexport const MIGRATION_005_A_POSICAO_E_CONSEQUENCIA_DO_MOVIMENTO = `-- A posição é consequência do movimento.\n--\n-- Desfaz a migration 004, que estava errada — e o registro do porquê vale mais\n-- que o código que sai.\n--\n-- A 004 criou um writer para trazer \\`stock_positions\\` do V1 como FATO, com o\n-- argumento de que derivar o saldo do movimento só dá o mesmo número quando o\n-- movimento atravessa inteiro. O argumento era bom e a premissa tinha deixado\n-- de valer no mesmo dia: os 2.697 movimentos passaram a atravessar inteiros\n-- assim que a entrada por DANFE ganhou o local (a ponte no extrator).\n--\n-- E o destino já dizia isso, em voz alta:\n--\n-- plg_inventory_stock_positions is written only through the inventory RPCs\n-- (inventory_receive / _transfer …)\n--\n-- 339 das 1.861 linhas bateram nesse gatilho. O gatilho está certo: no V2 a\n-- posição não é algo que se escreve, é o que sobra depois que o movimento\n-- passou. Escrever por fora seria manter duas verdades sobre o mesmo saldo e\n-- deixar a divergência para depois.\n--\n-- ── A prova ─────────────────────────────────────────────────────────────────\n--\n-- Medido em 19/09/2026 no tenant Pertinho do Céu, depois de os movimentos\n-- entrarem:\n--\n-- V1 stock_positions 1.861 linhas 251.561,2484\n-- V2 plg_inventory_stock_positions 990 linhas 251.561,2484\n--\n-- O SALDO é o mesmo até o quarto decimal. A contagem de linhas difere porque o\n-- V1 guarda uma posição por lote/validade e o V2 consolida por produto × local\n-- quando não há lote — duas formas de escrever o mesmo estoque, e é o estoque\n-- que se confere.\n--\n-- ── O que sai e o que fica ──────────────────────────────────────────────────\n--\n-- Sai a linha de \\`stock_positions\\` da allowlist. Fica \\`migration.excluded_tables\\`\n-- com o motivo medido, para que a próxima pessoa que vir 1.861 linhas paradas\n-- no dashboard leia a resposta em vez de refazer a investigação.\n--\n-- O writer \\`upsert_inv_position\\` FICA. Ele não faz mal parado, e um pool que\n-- porte posição sem portar movimento vai precisar dele — o que muda é que este\n-- não é esse caso.\n--\n-- Idempotente.\n\n-- A linha está CONGELADA, e o gatilho recusa DELETE nela pelo mesmo motivo que\n-- recusa UPDATE: mudança de core-A é arquivo de migration. Este é o arquivo, e\n-- a escotilha é transacional — não fica porta aberta depois dele.\nSELECT set_config('migration.allowlist_unlock', 'on', true);\nDELETE FROM migration.allowlist WHERE source_table = 'stock_positions';\nSELECT set_config('migration.allowlist_unlock', 'off', true);\n\n-- \\`WHERE tenant_id IS NULL\\` no árbitro: a 073 da espinha trocou a PK de\n-- \\`migration.excluded_tables\\` por dois índices únicos PARCIAIS — um global e\n-- um por inquilino —, porque \"não trazer esta tabela\" passou a ser decisão de\n-- cliente e não do cluster. Índice parcial só serve de árbitro de ON CONFLICT\n-- quando o comando repete o mesmo recorte. Esta decisão é global.\nINSERT INTO migration.excluded_tables (source_table, reason)\nVALUES ('stock_positions',\n 'Consequência, não fato: no V2 a posição só se escreve pelas RPCs de '\n 'inventário (o gatilho recusa INSERT direto), e ela se forma sozinha '\n 'quando o movimento atravessa. Conferido em 19/09/2026 no Pertinho do '\n 'Céu — V1 1.861 linhas / 251.561,2484 contra V2 990 linhas / '\n '251.561,2484: mesmo saldo, formas diferentes de agrupar (o V1 guarda '\n 'por lote, o V2 consolida sem lote).')\n-- \\`WHERE tenant_id IS NULL\\` porque a PK de \\`excluded_tables\\` deixou de existir:\n-- o spine 070 a trocou por dois índices únicos PARCIAIS — um por tabela global,\n-- outro por tabela e tenant. \\`ON CONFLICT (source_table)\\` sozinho não casa com\n-- índice parcial, e a cadeia do zero parou aqui com \"there is no unique or\n-- exclusion constraint matching the ON CONFLICT specification\".\n--\n-- Esta linha é global (sem tenant), então é o índice global que ela quer.\nON CONFLICT (source_table) WHERE tenant_id IS NULL DO UPDATE SET reason = EXCLUDED.reason;\n`\n\nexport const MIGRATION_006_A_PRODUCAO_TEM_ORDEM_E_ESTACAO = `-- A produção tem ordem e estação.\n--\n-- O Pertinho do Céu produz: pega insumo, passa por etapas, sai produto. Seis\n-- tabelas do V1 descrevem isso e nenhuma tinha destino.\n--\n-- production_orders 3 a ordem: o que produzir, quanto, quando\n-- production_order_inputs 27 o insumo consumido\n-- production_order_outputs 2 o que saiu\n-- production_order_steps 7 a etapa, na estação, com tempo\n-- production_plan_items 2 o plano do dia, antes de virar ordem\n-- production_stations 4 onde a etapa acontece\n--\n-- O volume é ridículo — 45 linhas — e é exatamente por isso que vale trazer: a\n-- casa está COMEÇANDO a usar produção, e o dia em que ela usar de verdade o\n-- histórico já vai estar do lado certo. Reconstituir depois é impossível: uma\n-- ordem de produção fechada diz quanto de insumo virou quanto de produto, e\n-- esse número não se recalcula.\n--\n-- ── A receita já existe, a ordem não existia ────────────────────────────────\n--\n-- \\`plg_inventory_recipes\\`, \\`_recipe_ingredients\\` e \\`_recipe_groups\\` já estão no\n-- V2: é a FICHA, o que a coisa leva. O que faltava é a EXECUÇÃO da ficha — a\n-- ordem que a aplica num dia, com o que realmente entrou e o que realmente\n-- saiu. \\`recipe_snapshot\\` guarda a ficha como ela era no dia, porque mudar a\n-- receita amanhã não pode reescrever a produção de ontem.\n--\n-- ── A estação é do KDS também ───────────────────────────────────────────────\n--\n-- \\`production_stations\\` do V1 carrega sete colunas de KDS (\\`kds_enabled\\`,\n-- \\`kds_role\\`, \\`kds_sla_minutes\\`…). O V2 já tem \\`plg_kds_stations\\` para isso, e\n-- duplicar a configuração do monitor aqui daria duas respostas para \"qual a SLA\n-- desta estação\". Então elas vão para \\`metadata.kds\\`, de onde o dia da migração\n-- do KDS as lê — e a estação de PRODUÇÃO fica com o que é dela: nome, unidade,\n-- se está ativa.\n--\n-- Idempotente.\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_stations (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n name text NOT NULL,\n description text,\n is_active boolean DEFAULT true NOT NULL,\n sort_order integer DEFAULT 0 NOT NULL,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_inventory_production_stations IS\n 'Onde a etapa de produção acontece. V1: production_stations — a configuração de KDS dela fica em metadata.kds, porque plg_kds_stations é quem responde por monitor.';\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_orders (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n order_number text,\n status text DEFAULT 'draft'::text NOT NULL,\n product_id uuid,\n recipe_id uuid,\n -- A ficha como ela era no dia. Mudar a receita amanhã não reescreve a\n -- produção de ontem.\n recipe_snapshot jsonb,\n planned_quantity numeric(18,4),\n measurement_unit_id uuid,\n planned_start timestamp with time zone,\n planned_end timestamp with time zone,\n actual_start timestamp with time zone,\n actual_end timestamp with time zone,\n source_type text,\n priority integer DEFAULT 0 NOT NULL,\n notes text,\n owner_id uuid,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL,\n CONSTRAINT plg_inventory_production_orders_window_check\n CHECK (actual_start IS NULL OR actual_end IS NULL OR actual_end >= actual_start)\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_steps (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n production_order_id uuid NOT NULL,\n station_id uuid,\n sequence integer DEFAULT 0 NOT NULL,\n name text,\n instructions text,\n estimated_minutes integer,\n status text DEFAULT 'pending'::text NOT NULL,\n started_at timestamp with time zone,\n completed_at timestamp with time zone,\n -- O V1 guarda o nome do operador em texto, sem FK. Fica texto: inventar uma\n -- pessoa a partir de um nome digitado é como se cria cadastro duplicado.\n operator_name text,\n notes text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_inputs (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n production_order_id uuid NOT NULL,\n step_id uuid,\n product_id uuid NOT NULL,\n -- Planejado contra real: é a diferença entre os dois que diz se a ficha\n -- está certa. Guardar só o real perderia a pergunta.\n planned_quantity numeric(18,4),\n actual_quantity numeric(18,4),\n measurement_unit_id uuid,\n stock_position_id uuid,\n unit_cost numeric(18,6),\n consumed_at timestamp with time zone,\n operator_name text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_outputs (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n production_order_id uuid NOT NULL,\n product_id uuid NOT NULL,\n -- Principal, subproduto ou perda. É a palavra que separa rendimento de\n -- desperdício, e sem ela a conta de custo não fecha.\n output_type text DEFAULT 'main'::text NOT NULL,\n planned_quantity numeric(18,4),\n actual_quantity numeric(18,4),\n measurement_unit_id uuid,\n batch_number text,\n expiration_date date,\n stock_position_id uuid,\n unit_cost numeric(18,6),\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_production_plan_items (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n plan_date date NOT NULL,\n product_id uuid NOT NULL,\n planned_quantity numeric(18,4),\n measurement_unit_id uuid,\n status text DEFAULT 'planned'::text NOT NULL,\n -- A ordem que o plano virou, quando virou. Nulo é plano ainda não liberado.\n production_order_id uuid,\n notes text,\n metadata jsonb DEFAULT '{}'::jsonb NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_inventory_production_plan_items IS\n 'O que se pretende produzir naquele dia, antes de virar ordem. V1: production_plan_items.';\n\n-- ── chaves ──────────────────────────────────────────────────────────────────\nDO $$\nDECLARE t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_inventory_production_stations', 'plg_inventory_production_orders',\n 'plg_inventory_production_steps', 'plg_inventory_production_inputs',\n 'plg_inventory_production_outputs', 'plg_inventory_production_plan_items'] LOOP\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = ('public.' || t)::regclass AND contype = 'p') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I PRIMARY KEY (id)', t, t || '_pkey');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_id_id_key') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I UNIQUE (tenant_id, id)', t, t || '_tenant_id_id_key');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_fkey') THEN\n EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE', t, t || '_tenant_fkey');\n END IF;\n END LOOP;\nEND $$;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_stations_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_stations ADD CONSTRAINT plg_inventory_production_stations_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_orders_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_orders ADD CONSTRAINT plg_inventory_production_orders_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_orders_product_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_orders ADD CONSTRAINT plg_inventory_production_orders_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_orders_recipe_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_orders ADD CONSTRAINT plg_inventory_production_orders_recipe_fkey\n FOREIGN KEY (recipe_id) REFERENCES public.plg_inventory_recipes(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_orders_uom_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_orders ADD CONSTRAINT plg_inventory_production_orders_uom_fkey\n FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_steps_order_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_steps ADD CONSTRAINT plg_inventory_production_steps_order_fkey\n FOREIGN KEY (tenant_id, production_order_id) REFERENCES public.plg_inventory_production_orders(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_steps_station_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_steps ADD CONSTRAINT plg_inventory_production_steps_station_fkey\n FOREIGN KEY (station_id) REFERENCES public.plg_inventory_production_stations(id) ON DELETE SET NULL;\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_inputs_order_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_inputs ADD CONSTRAINT plg_inventory_production_inputs_order_fkey\n FOREIGN KEY (tenant_id, production_order_id) REFERENCES public.plg_inventory_production_orders(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_inputs_step_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_inputs ADD CONSTRAINT plg_inventory_production_inputs_step_fkey\n FOREIGN KEY (step_id) REFERENCES public.plg_inventory_production_steps(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_inputs_product_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_inputs ADD CONSTRAINT plg_inventory_production_inputs_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_inputs_uom_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_inputs ADD CONSTRAINT plg_inventory_production_inputs_uom_fkey\n FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_outputs_order_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_outputs ADD CONSTRAINT plg_inventory_production_outputs_order_fkey\n FOREIGN KEY (tenant_id, production_order_id) REFERENCES public.plg_inventory_production_orders(tenant_id, id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_outputs_product_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_outputs ADD CONSTRAINT plg_inventory_production_outputs_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_outputs_uom_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_outputs ADD CONSTRAINT plg_inventory_production_outputs_uom_fkey\n FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_plan_items_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_plan_items ADD CONSTRAINT plg_inventory_production_plan_items_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_plan_items_product_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_plan_items ADD CONSTRAINT plg_inventory_production_plan_items_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_production_plan_items_order_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_production_plan_items ADD CONSTRAINT plg_inventory_production_plan_items_order_fkey\n FOREIGN KEY (production_order_id) REFERENCES public.plg_inventory_production_orders(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_production_orders_number_uidx\n ON public.plg_inventory_production_orders USING btree (tenant_id, order_number)\n WHERE order_number IS NOT NULL;\nCREATE INDEX IF NOT EXISTS plg_inventory_production_orders_open_idx\n ON public.plg_inventory_production_orders USING btree (tenant_id, unit_id, status, planned_start);\nCREATE INDEX IF NOT EXISTS plg_inventory_production_steps_order_idx\n ON public.plg_inventory_production_steps USING btree (tenant_id, production_order_id, sequence);\nCREATE INDEX IF NOT EXISTS plg_inventory_production_inputs_order_idx\n ON public.plg_inventory_production_inputs USING btree (tenant_id, production_order_id);\nCREATE INDEX IF NOT EXISTS plg_inventory_production_inputs_product_idx\n ON public.plg_inventory_production_inputs USING btree (tenant_id, product_id, consumed_at DESC);\nCREATE INDEX IF NOT EXISTS plg_inventory_production_outputs_order_idx\n ON public.plg_inventory_production_outputs USING btree (tenant_id, production_order_id);\nCREATE INDEX IF NOT EXISTS plg_inventory_production_plan_items_day_idx\n ON public.plg_inventory_production_plan_items USING btree (tenant_id, unit_id, plan_date);\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_production_stations_name_uidx\n ON public.plg_inventory_production_stations USING btree (tenant_id, unit_id, lower(name))\n WHERE unit_id IS NOT NULL;\n\n-- RLS, uma a uma e por extenso. O laço adiante já liga tudo isto — mas ele liga\n-- por \\`EXECUTE format(...)\\`, e o portão que revisa plugin lê o ARQUIVO, não o\n-- banco: para ele, tabela com tenant_id e sem um ENABLE literal é tabela\n-- aberta. Uma garantia que o revisor não consegue ler é uma garantia que\n-- ninguém confere.\nALTER TABLE public.plg_inventory_production_stations ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_production_orders ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_production_steps ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_production_inputs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_production_outputs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_production_plan_items ENABLE ROW LEVEL SECURITY;\n\nDO $$\nDECLARE t text;\nDECLARE tem_unidade boolean;\nBEGIN\n FOREACH t IN ARRAY ARRAY['plg_inventory_production_stations', 'plg_inventory_production_orders',\n 'plg_inventory_production_steps', 'plg_inventory_production_inputs',\n 'plg_inventory_production_outputs', 'plg_inventory_production_plan_items'] LOOP\n tem_unidade := t IN ('plg_inventory_production_stations', 'plg_inventory_production_orders',\n 'plg_inventory_production_plan_items');\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', t || '_updated_at', t);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()', t || '_updated_at', t);\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', t);\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.%I TO authenticated', t);\n EXECUTE format('GRANT ALL ON TABLE public.%I TO service_role', t);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_select', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (%s)\n AND (SELECT app.has_permission('inventory.read', %s)))$f$,\n t || '_authz_select', t,\n CASE WHEN tem_unidade THEN format('unit_id IS NULL OR (SELECT app.has_unit(%I.unit_id))', t) ELSE 'true' END,\n CASE WHEN tem_unidade THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_write', t);\n EXECUTE format($f$CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('inventory.edit', %s)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('inventory.edit', %s)))$f$,\n t || '_authz_write', t,\n CASE WHEN tem_unidade THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END,\n CASE WHEN tem_unidade THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);\n END LOOP;\nEND $$;\n\nINSERT INTO public.scoped_resources (resource_table, unit_column, owner_column, shareable, default_visibility, label)\nVALUES ('plg_inventory_production_orders', 'unit_id', 'owner_id', false, 'unit', 'Ordens de produção')\nON CONFLICT (resource_table) DO UPDATE\n SET unit_column = EXCLUDED.unit_column, default_visibility = EXCLUDED.default_visibility, label = EXCLUDED.label;\n`\n\nexport const MIGRATION_007_A_PRODUCAO_ATRAVESSA = `-- A produção atravessa.\n--\n-- A 006 fez as seis tabelas. Esta escreve o de-para com \\`by_shape\\` (spine 123).\n-- A ordem importa: estação antes da etapa, ordem antes de tudo que pendura\n-- nela, e o plano por último porque ele aponta para a ordem que gerou.\n--\n-- ── A configuração de KDS não vem para cá ───────────────────────────────────\n--\n-- \\`production_stations\\` carrega sete colunas de KDS (\\`kds_enabled\\`, \\`kds_role\\`,\n-- \\`kds_sla_minutes\\`…). Elas vão para \\`metadata.kds\\` e não para coluna: o V2 tem\n-- \\`plg_kds_stations\\`, e duplicar a configuração do monitor aqui daria duas\n-- respostas para \"qual a SLA desta estação\". Quando o KDS portar, ele lê o\n-- metadata e a estação de produção fica com o que é dela.\n--\n-- ── O movimento de estoque fica como referência ─────────────────────────────\n--\n-- \\`stock_movement_uuid\\` no insumo e no produto aponta para a baixa/entrada que\n-- a produção gerou. Vem como referência em metadata, não como FK: o movimento\n-- atravessa por outro caminho (\\`stock_movements\\`) e amarrar os dois aqui\n-- exigiria que a ordem de produção esperasse o razão — uma dependência que o\n-- volume (45 linhas) não justifica.\n--\n-- Idempotente.\n\nSET LOCAL migration.allowlist_unlock = 'on';\n\nSELECT migration._allow(\n 'production_stations', 'public.plg_inventory_production_stations', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_stations'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'name', 'name',\n 'description', 'description',\n 'active', 'is_active',\n 'kds_display_order', 'sort_order',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'unit_id', '-',\n 'kds_enabled', 'jsonb:kds.enabled',\n 'kds_role', 'jsonb:kds.role',\n 'is_kds_fallback', 'jsonb:kds.is_fallback',\n 'kds_sla_minutes', 'jsonb:kds.sla_minutes',\n 'kds_catalog_mode', 'jsonb:kds.catalog_mode',\n 'kds_config_version', 'jsonb:kds.config_version',\n 'id', 'jsonb:inventory.v1_ref'),\n 'Onde a etapa acontece. \\`unit_id\\` da origem é uuid de companies e não o id '\n 'numérico que o ledger resolve — a unidade vem pelo augment do extrator. A '\n 'configuração de KDS fica em metadata.kds porque plg_kds_stations é quem '\n 'responde por monitor.'\n);\n\nSELECT migration._allow(\n 'production_orders', 'public.plg_inventory_production_orders', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_orders'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies',\n 'order_number', 'order_number',\n 'status', 'status',\n 'product_id', 'product_id@products',\n 'recipe_id', 'recipe_id@recipes',\n 'recipe_snapshot', 'recipe_snapshot',\n 'planned_qty', 'planned_quantity',\n 'unit_id_measure', 'measurement_unit_id@measurement_units',\n 'planned_start', 'planned_start',\n 'planned_end', 'planned_end',\n 'actual_start', 'actual_start',\n 'actual_end', 'actual_end',\n 'source_type', 'source_type',\n 'priority', 'priority',\n 'notes', 'notes',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'created_by', '-',\n 'released_by', '-',\n 'finished_by', '-',\n 'id', 'jsonb:inventory.v1_ref'),\n 'A ordem de produção. \\`recipe_snapshot\\` é a ficha como ela era no dia — '\n 'mudar a receita amanhã não pode reescrever a produção de ontem.'\n);\n\nSELECT migration._allow(\n 'production_order_steps', 'public.plg_inventory_production_steps', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_steps'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'order_id', 'production_order_id@production_orders',\n 'production_station_id', 'station_id@production_stations',\n 'sequence', 'sequence',\n 'name', 'name',\n 'instructions', 'instructions',\n 'estimated_minutes', 'estimated_minutes',\n 'status', 'status',\n 'started_at', 'started_at',\n 'completed_at', 'completed_at',\n 'operator_name', 'operator_name',\n 'notes', 'notes',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:inventory.v1_ref'),\n 'A etapa, na estação, com tempo. \\`operator_name\\` continua texto: inventar uma '\n 'pessoa a partir de um nome digitado é como se cria cadastro duplicado.'\n);\n\nSELECT migration._allow(\n 'production_order_inputs', 'public.plg_inventory_production_inputs', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_inputs'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'order_id', 'production_order_id@production_orders',\n 'step_id', 'step_id@production_order_steps',\n 'product_id', 'product_id@products',\n 'planned_qty', 'planned_quantity',\n 'actual_qty', 'actual_quantity',\n 'unit_id', 'measurement_unit_id@measurement_units',\n 'stock_position_id', 'stock_position_id@stock_positions',\n 'unit_cost', 'unit_cost',\n 'consumed_at', 'consumed_at',\n 'operator_name', 'operator_name',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'product_uuid', '-',\n 'unit_label_id', '-',\n 'stock_movement_uuid', 'jsonb:inventory.v1_stock_movement_ref',\n 'id', 'jsonb:inventory.v1_ref'),\n 'O insumo consumido. Planejado E real: é a diferença entre os dois que diz se '\n 'a ficha está certa. \\`unit_id\\` aqui é UNIDADE DE MEDIDA, não filial — o nome '\n 'da coluna do V1 engana, e por isso o destino se chama measurement_unit_id.'\n);\n\nSELECT migration._allow(\n 'production_order_outputs', 'public.plg_inventory_production_outputs', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_outputs'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'order_id', 'production_order_id@production_orders',\n 'product_id', 'product_id@products',\n 'output_type', 'output_type',\n 'planned_qty', 'planned_quantity',\n 'actual_qty', 'actual_quantity',\n 'unit_id', 'measurement_unit_id@measurement_units',\n 'batch_number', 'batch_number',\n 'expiration_date', 'expiration_date',\n 'stock_position_id', 'stock_position_id@stock_positions',\n 'unit_cost', 'unit_cost',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'product_uuid', '-',\n 'stock_movement_uuid', 'jsonb:inventory.v1_stock_movement_ref',\n 'id', 'jsonb:inventory.v1_ref'),\n 'O que saiu: principal, subproduto ou perda. É essa palavra que separa '\n 'rendimento de desperdício, e sem ela a conta de custo não fecha.'\n);\n\nSELECT migration._allow(\n 'production_plan_items', 'public.plg_inventory_production_plan_items', 'inventory', 'by_shape',\n jsonb_build_object('target', 'public.plg_inventory_production_plan_items'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies',\n 'plan_date', 'plan_date',\n 'product_id', 'product_id@products',\n 'planned_qty', 'planned_quantity',\n 'unit_id_measure', 'measurement_unit_id@measurement_units',\n 'status', 'status',\n 'production_order_id', 'production_order_id@production_orders',\n 'notes', 'notes',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'id', 'jsonb:inventory.v1_ref'),\n 'O que se pretende produzir naquele dia, antes de virar ordem. Vem por último '\n 'porque aponta para a ordem que ele gerou.'\n);\n\nDELETE FROM migration.excluded_tables\n WHERE source_table IN ('production_stations', 'production_orders', 'production_order_steps',\n 'production_order_inputs', 'production_order_outputs', 'production_plan_items');\n\nRESET migration.allowlist_unlock;\n`\n\nexport const MIGRATION_008_O_GRUPO_DA_RECEITA_TAMBEM_E_DE_UMA_CASA = `-- O grupo da receita também é de uma casa.\n--\n-- \\`plg_inventory_recipes\\` e \\`plg_inventory_recipe_ingredients\\` já carregam\n-- \\`unit_id\\`. \\`plg_inventory_recipe_groups\\` — que é irmão dos dois e agrupa\n-- ingredientes alternativos dentro da mesma ficha — ficou sem.\n--\n-- São 172 grupos no Pertinho do Céu. Sem a coluna, o grupo de uma cozinha\n-- aparece na ficha da outra, e a substituição de ingrediente sugere um produto\n-- que aquela casa não tem em estoque.\n--\n-- Idempotente.\n\nALTER TABLE public.plg_inventory_recipe_groups ADD COLUMN IF NOT EXISTS unit_id uuid;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_groups_unit_fkey') THEN\n ALTER TABLE public.plg_inventory_recipe_groups ADD CONSTRAINT plg_inventory_recipe_groups_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\nCOMMENT ON COLUMN public.plg_inventory_recipe_groups.unit_id IS\n 'A cozinha a que o grupo pertence — as irmãs plg_inventory_recipes e _recipe_ingredients já a tinham (008).';\n\nCREATE INDEX IF NOT EXISTS plg_inventory_recipe_groups_unit_idx\n ON public.plg_inventory_recipe_groups USING btree (tenant_id, unit_id);\n`\n\nexport const MIGRATION_009_A_DIRECAO_DO_MOVIMENTO_NAO_ESTA_NO_NUMERO = `-- A direção do movimento não está no número — e o V2 guarda ela lá.\n--\n-- \\`plg_inventory_stock_movements\\` assina a quantidade. O CHECK diz isso em voz\n-- alta desde o baseline:\n--\n-- plg_inventory_stock_movements_sign_check\n-- (kind = 'in' AND quantity > 0)\n-- OR (kind = 'out' AND quantity < 0)\n-- OR (kind = 'transfer' AND quantity < 0)\n-- OR kind IN ('adjust', 'reverse')\n--\n-- E não é decoração: \\`app.inventory_movements_after_insert\\` soma \\`NEW.quantity\\`\n-- na posição de origem e \\`-NEW.quantity\\` na de destino. O sinal É o efeito no\n-- saldo. Uma saída positiva não seria recusada por capricho — ela AUMENTARIA o\n-- estoque.\n--\n-- O V1 guarda a direção em outro lugar: no \\`movement_type\\`. O número é sempre a\n-- magnitude. Medido em 21/09/2026 sobre os 2.997 movimentos do banco inteiro,\n-- todos os inquilinos:\n--\n-- entrada 2.871 menor 0,001 maior 10.000 negativos: 0\n-- saida 119 menor 0,2 maior 26 negativos: 0\n-- ajuste 6 menor 1 maior 1 negativos: 0\n-- transferencia 1 menor 1 maior 1 negativos: 0\n--\n-- \\`migration.upsert_inv_movement\\` traduzia o RÓTULO (\\`saida\\` → \\`out\\`) e passava\n-- o número adiante intacto. Ou seja: toda saída e toda transferência do V1 era\n-- uma violação de constraint garantida. Isso ficou dois inquilinos sem\n-- aparecer porque o Pertinho do Céu só tem entrada — 2.707 de 2.707. O Espaço\n-- Facial é o primeiro com saída, e as três saídas dele que tinham local\n-- bateram na constraint:\n--\n-- state: 23514: ... violates check constraint\n-- \"plg_inventory_stock_movements_sign_check\" ×3\n--\n-- ── O ajuste é o caso que não se resolve pelo rótulo ─────────────────────────\n--\n-- \\`entrada\\`, \\`saida\\` e \\`transferencia\\` dizem a direção no nome. \\`ajuste\\` não:\n-- ele tanto acha quanto perde, e o V1 escreve 1 nos dois casos. Quem sabe é a\n-- contagem que o gerou — \\`stock_count_items.counted_qty - system_qty_at_review\\`\n-- é a diferença apurada, com sinal. Conferido nos 4 ajustes de inventário do\n-- Espaço Facial: os dois \"falta apurada\" dão -1, os dois \"sobra apurada\" dão\n-- +1. O extrator passou a mandar isso como \\`adjust_delta\\` (ver\n-- fayz-etl/fayz_etl/sources/beautysoft_v1.py, passo \\`stock_movements\\`), e o\n-- de-para abaixo abre a porta para a coluna.\n--\n-- Quando o ajuste não vem de contagem, \\`adjust_delta\\` chega nulo — e aí a\n-- linha vai para a quarentena em vez de entrar com o sinal chutado. São 2\n-- linhas hoje (\"Correção de auditoria (estorno)\"), e as duas já estavam\n-- paradas por falta de local. Somar onde era para subtrair é o erro que\n-- ninguém vê: ele não quebra nada, só deixa o saldo errado.\n--\n-- ── O que NÃO muda ──────────────────────────────────────────────────────────\n--\n-- A guarda de entrada continua exigindo \\`quantity > 0\\`: o writer recebe do V1,\n-- e no V1 a direção é o tipo, não o sinal. O que muda é a SAÍDA dele — a\n-- tradução para a convenção da tabela de destino, que é onde ela sempre\n-- deveria ter acontecido. As 2.208 + 47 entradas já migradas não se movem: para\n-- \\`in\\`, assinado e magnitude são o mesmo número, e a tabela é append-only.\n--\n-- Idempotente: CREATE OR REPLACE e um UPDATE de jsonb por concatenação.\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 1. O writer assina o número\n-- ─────────────────────────────────────────────────────────────────────────────\n\nCREATE OR REPLACE FUNCTION migration.upsert_inv_movement(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_kind_raw text := nullif(btrim(lower(coalesce(p_row ->> 'kind', ''))), '');\n v_kind text := CASE v_kind_raw\n WHEN 'in' THEN 'in' WHEN 'out' THEN 'out'\n WHEN 'transfer' THEN 'transfer' WHEN 'adjust' THEN 'adjust' WHEN 'reverse' THEN 'reverse'\n -- the SDK's legacy labels, and V1's pt-BR\n WHEN 'entry' THEN 'in' WHEN 'entrada' THEN 'in'\n WHEN 'exit' THEN 'out' WHEN 'saida' THEN 'out' WHEN 'saída' THEN 'out'\n WHEN 'loss' THEN 'out' WHEN 'perda' THEN 'out'\n WHEN 'adjustment' THEN 'adjust' WHEN 'ajuste' THEN 'adjust'\n WHEN 'transferencia' THEN 'transfer' WHEN 'transferência' THEN 'transfer'\n END;\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n -- A magnitude, como a origem a manda, e o número ASSINADO que a tabela pede.\n -- Os dois existem porque são contratos de lados diferentes da fronteira.\n v_qty numeric := coalesce((p_row ->> 'quantity')::numeric, 0);\n v_delta numeric := (p_row ->> 'adjust_delta')::numeric;\n v_signed numeric;\n v_exists boolean;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR (p_row ->> 'product_id') IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk', 'reason', 'a stock movement needs an id and its product');\n END IF;\n IF v_kind IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('unknown movement type %L (expected in|out|transfer|adjust|reverse, or a V1 label of one)', coalesce(v_kind_raw, '<null>')));\n END IF;\n IF v_qty <= 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value', 'reason', 'a stock movement needs a quantity > 0 — direction is the kind, not the sign');\n END IF;\n IF v_kind = 'transfer' AND (p_row ->> 'destination_location_id') IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state', 'reason', 'a transfer needs its destination location');\n END IF;\n\n -- A tradução. O rótulo diz a direção em três dos cinco tipos; no ajuste ela\n -- vem da contagem, e sem ela não se inventa.\n IF v_kind = 'adjust' THEN\n IF v_delta IS NULL OR v_delta = 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', 'an adjustment does not say which way it goes — the V1 writes the size and leaves the sign to the count it came from (adjust_delta)');\n END IF;\n v_signed := sign(v_delta) * v_qty;\n ELSIF v_kind IN ('out', 'transfer') THEN\n v_signed := -v_qty;\n ELSE\n -- 'in' e 'reverse'. O estorno mantém a magnitude: o sign_check o dispensa,\n -- e quem decide o sentido dele é o movimento que ele desfaz.\n v_signed := v_qty;\n END IF;\n\n SELECT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements WHERE id = p_id) INTO v_exists;\n IF v_exists THEN\n -- the ledger is append-only: a second offer of the same movement is a replay,\n -- not an update. Nothing to do, and saying \"migrated\" again is honest —\n -- the destination already holds exactly this row.\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'reason', 'already in the ledger (append-only)');\n END IF;\n\n -- 005's single-writer gate refuses any write \"however privileged\" unless this\n -- is set. The migration IS one of the internal writers — definer-only, fenced\n -- and audited — so it declares itself rather than being exempted, and the\n -- after-insert trigger derives the position from what it writes.\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n INSERT INTO public.plg_inventory_stock_movements\n (id, tenant_id, product_id, kind, quantity, unit_cost, total_cost,\n source_location_id, destination_location_id, batch_number, expiration_date,\n document_number, reason, notes, movement_date, metadata)\n VALUES (p_id, p_tenant, (p_row ->> 'product_id')::uuid, v_kind,\n v_signed,\n (p_row ->> 'unit_cost')::numeric, (p_row ->> 'total_cost')::numeric,\n (p_row ->> 'source_location_id')::uuid, (p_row ->> 'destination_location_id')::uuid,\n p_row ->> 'batch_number', (p_row ->> 'expiration_date')::date,\n p_row ->> 'document_number', p_row ->> 'reason', p_row ->> 'notes',\n coalesce((p_row ->> 'movement_date')::timestamptz, now()), v_meta);\n PERFORM set_config('fayz.inventory_internal', 'off', true);\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_inventory_stock_movements', p_id, jsonb_build_object('reason', 'created')); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'reason', 'created');\nEND $function$;\n\nCOMMENT ON FUNCTION migration.upsert_inv_movement(uuid, uuid, jsonb, jsonb) IS\n 'Movimento de estoque do V1 para o V2. Recebe magnitude + tipo (a convenção do V1) e grava quantidade ASSINADA (a convenção da tabela). A direção do ajuste vem de adjust_delta — ver 009.';\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 2. O de-para abre a porta para a direção do ajuste\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- \\`adjust_delta\\` não é coluna do V1: é derivada pelo plano de leitura, a partir\n-- de \\`stock_count_items\\`. Entra no mapa como campo simples porque é isso que\n-- ela é no \\`p_row\\` — o writer lê e não grava, então ela não precisa (nem pode)\n-- casar com coluna do destino.\n\nSET LOCAL migration.allowlist_unlock = 'on';\n\nUPDATE migration.allowlist\n SET columns = columns || jsonb_build_object('adjust_delta', 'adjust_delta')\n WHERE source_table = 'stock_movements';\n\nRESET migration.allowlist_unlock;\n`\n\nexport const MIGRATION_010_A_ENTRADA_DE_NOTAS_ATRAVESSA = `-- A entrada de notas atravessa.\n--\n-- A importação de DANFE do V1 — 607 notas (527 no Pertinho do Céu, 80 no\n-- Espaço Facial), 3.008 linhas, 68 lotes — não tinha nenhuma linha na\n-- \\`migration.allowlist\\`. Este arquivo escreve a dela e a das linhas; a parcela,\n-- que é do financeiro, mora em plugin-financial/084 (o financeiro roda ANTES do\n-- inventário na corrente, então o de-para dela não podia vir por aqui).\n--\n-- ── O achado que mudou o desenho: a linha da nota JÁ é o movimento ──────────\n--\n-- O caminho óbvio seria \\`danfe_import_items\\` → \\`plg_inventory_stock_movements\\`.\n-- Medido em 21/09/2026 no V1 de produção, ele DOBRARIA o estoque:\n--\n-- tenant 8: 2.707 dos 2.860 itens (94,7%) já têm um \\`stock_movements\\` no V1,\n-- e a tabela \\`stock_movements\\` do tenant 8 é INTEIRA de DANFE —\n-- 2.707 de 2.707 linhas com \\`danfe_import_item_id\\`.\n-- ledger: 2.757 movimentos já atravessaram (\\`status = 'migrated'\\`).\n--\n-- Quantidade e custo batem linha a linha (o movimento é gerado pela conciliação\n-- da nota). Criar um segundo movimento a partir do item somaria a mesma entrada\n-- duas vezes — e, pior, o gatilho \\`plg_inventory_stock_movements_after_insert\\`\n-- deriva a POSIÇÃO do movimento, então o saldo dobraria junto, sem ninguém\n-- acusar.\n--\n-- Então a linha da nota não cria movimento: ela ADOTA o que já atravessou.\n-- \\`movement_uuid\\` resolve pelo ledger de \\`stock_movements\\`, o writer devolve\n-- aquele id como \\`target_id\\`, e o conteúdo da linha — o que o movimento não\n-- carrega: NCM, CFOP, tributo, fator de conversão, produto sugerido pela IA —\n-- vai para o \\`result\\` da operação, que é onde o V2 já guarda o que uma operação\n-- de inventário produziu (\\`app.inventory_movement_json\\`, \\`inventory_receive\\`).\n--\n-- Item sem movimento no V1 (153 no tenant 8, 114 no tenant 1) é linha que nunca\n-- virou estoque: entra no \\`result\\` e fica \\`skipped\\`. O porte não inventa\n-- entrada que a origem não fez.\n--\n-- ── E o conteúdo FISCAL da nota também já atravessa ─────────────────────────\n--\n-- 607 de 607 notas têm a contraparte em \\`dfe_inbox\\` pela chave de acesso, e as\n-- 607 têm o MESMO número de linhas em \\`dfe_inbox_items\\` (149 = 149 no tenant 1,\n-- 2.859 = 2.859 no tenant 8). O XML, o tributo por coluna e a duplicata já vão\n-- para \\`plg_fiscalbr_inbox_*\\` por fiscal_br/003. Copiar tudo de novo aqui daria\n-- duas respostas para \"qual o ICMS desta linha\".\n--\n-- O que NÃO atravessava é a DECISÃO DE ENTRADA feita sobre a nota: a qual\n-- produto a linha foi ligada, em que unidade de estoque, com que fator de\n-- conversão, em que conta contábil, e o plano de pagamento que o operador\n-- montou. É isso que este arquivo traz.\n--\n-- ── A nota é uma operação de recebimento ────────────────────────────────────\n--\n-- \\`plg_inventory_operations\\` é o razão de operações do inventário, com\n-- vocabulário fechado (\\`receive | transfer | adjust | reserve | confirm |\n-- reverse\\`). Uma importação de DANFE é um \\`receive\\`, e a \\`idempotency_key\\` dela\n-- é a CHAVE DE ACESSO: 607 de 607 notas têm chave, e ela é única dentro do\n-- tenant nas duas casas. Isso faz o \\`op.idempotency_key = doc.access_key\\`\n-- ligar a operação ao documento fiscal sem coluna nova e sem FK entre plugins\n-- (o fiscal_br roda DEPOIS do inventário).\n--\n-- ── A coluna que eu tive de criar ───────────────────────────────────────────\n--\n-- \\`plg_inventory_operations\\` não tinha \\`metadata\\`. Sem ela o \\`by_shape\\` joga\n-- fora EM SILÊNCIO tudo que não casa com uma coluna do destino — que aqui são\n-- os 20 campos da nota — e joga fora também a proveniência que\n-- \\`_upsert_row_impl\\` carimba em toda linha portada (\\`migration.source_table\\`,\n-- \\`source_numeric_id\\`, \\`batch_id\\`). Seriam 607 notas no V2 sem como dizer de\n-- onde vieram. É a única coluna nova deste arquivo.\n--\n-- Idempotente.\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 1. A operação ganha onde guardar a nota\n-- ─────────────────────────────────────────────────────────────────────────────\n\nALTER TABLE public.plg_inventory_operations\n ADD COLUMN IF NOT EXISTS metadata jsonb NOT NULL DEFAULT '{}'::jsonb;\n\nCOMMENT ON COLUMN public.plg_inventory_operations.metadata IS\n 'O que a operação carrega e nenhuma coluna nomeia. No porte é a nota de '\n 'entrada inteira (metadata.danfe) e a proveniência da linha (metadata.migration). '\n 'A identidade da nota fica em idempotency_key, que é a chave de acesso.';\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 2. O writer genérico com a porteira do inventário aberta\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- \\`migration.upsert_by_shape\\` (spine 123/124) resolve o upsert desta tabela\n-- sozinho: as colunas do destino já têm o nome que o de-para produz. O que ele\n-- NÃO faz é abrir a porteira \\`fayz.inventory_internal\\`, e as três tabelas de\n-- inventário recusam qualquer escrita sem ela — inclusive a do porte, que é\n-- definer e cercada:\n--\n-- inventory: plg_inventory_operations is written only through the inventory RPCs\n--\n-- Foi essa frase que pôs 339 posições em quarentena na 004 e que a 005 acabou\n-- dando por certa. Ela continua certa para a POSIÇÃO — a 005 tirou\n-- \\`stock_positions\\` da allowlist porque o saldo é consequência do movimento —\n-- e não diz nada contra a OPERAÇÃO, que é um fato do V1 e não um derivado de\n-- nada. O que ela exige é que quem escreve se declare.\n--\n-- Em vez de copiar o by_shape inteiro só para acrescentar duas linhas, este\n-- writer abre a porteira, delega, e fecha. A porteira é transacional\n-- (\\`set_config(..., true)\\`): ela morre com a transação e não vaza para a linha\n-- seguinte do lote.\n\nCREATE OR REPLACE FUNCTION migration.upsert_inv_shape(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_prev text := coalesce(current_setting('fayz.inventory_internal', true), 'off');\n v_res jsonb;\nBEGIN\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n v_res := migration.upsert_by_shape(p_tenant, p_id, p_row, p_args);\n PERFORM set_config('fayz.inventory_internal', v_prev, true);\n RETURN v_res;\nEND $function$;\n\nCOMMENT ON FUNCTION migration.upsert_inv_shape(uuid, uuid, jsonb, jsonb) IS\n 'upsert_by_shape com fayz.inventory_internal ligado. Para a tabela de inventário '\n 'que já tem a forma certa e cuja porteira de escrita única recusaria o porte.';\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 3. O writer da linha da nota — adota, nunca duplica\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- Serve as duas partes da nota, escolhidas por \\`writer_args.part\\`:\n--\n-- 'item' a linha da nota → o MOVIMENTO que ela gerou no V1\n-- 'batch' o lote da linha → a POSIÇÃO que aquele movimento derivou\n--\n-- Nenhuma das duas insere: as duas devolvem o id do que já está lá. É a única\n-- forma de a linha atravessar sem somar estoque duas vezes, porque\n-- \\`plg_inventory_stock_movements\\` é append-only (o gatilho recusa até um UPDATE\n-- que só acrescente coluna nula) e a posição é consequência do movimento.\n--\n-- O conteúdo da linha vai para \\`plg_inventory_operations.result\\`, indexado pelo\n-- id da linha — objeto e não lista, para a segunda oferta da mesma linha\n-- substituir a primeira em vez de empilhar.\n\nCREATE OR REPLACE FUNCTION migration.upsert_inv_danfe_line(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_part text := coalesce(p_args ->> 'part', 'item');\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_operation uuid := (p_row ->> 'operation_id')::uuid;\n v_movement uuid := (p_row ->> 'movement_id')::uuid;\n v_product uuid := (p_row ->> 'product_id')::uuid;\n v_location uuid := (p_row ->> 'stock_location_id')::uuid;\n v_target uuid;\n v_linha jsonb;\n v_prev text;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n\n IF p_id IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma linha de nota precisa de id');\n END IF;\n IF v_operation IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', 'linha de nota cuja importação ainda não atravessou');\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.plg_inventory_operations o\n WHERE o.id = v_operation AND o.tenant_id = p_tenant) THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('a operação %s não existe neste tenant', v_operation));\n END IF;\n\n -- O que atravessa da linha: tudo que o movimento não nomeia. Fica no \\`result\\`\n -- da operação, que é onde o V2 guarda o que uma operação produziu.\n -- \\`coalesce\\` porque \\`NULL || jsonb\\` é NULL, e uma nota sem nenhum campo de\n -- linha mapeado apagaria o registro inteiro em silêncio.\n v_linha := jsonb_strip_nulls(\n coalesce(v_meta -> 'danfe' -> CASE WHEN v_part = 'batch' THEN 'batch' ELSE 'line' END, '{}'::jsonb)\n || jsonb_build_object(\n 'movement_id', to_jsonb(v_movement),\n 'product_id', to_jsonb(v_product),\n 'line_no', p_row -> 'line_no',\n 'quantity', p_row -> 'quantity',\n 'batch_number', p_row -> 'batch_number',\n 'expiration_date', p_row -> 'expiration_date'));\n\n IF v_part = 'batch' THEN\n -- O lote não cria posição: ele aponta para a que o movimento derivou. A\n -- chave da posição é (tenant, produto, local, lote, validade) — a mesma que\n -- \\`app.inventory_apply_to_position\\` usa para decidir se soma ou cria.\n IF v_movement IS NOT NULL AND v_product IS NOT NULL AND v_location IS NOT NULL THEN\n SELECT sp.id INTO v_target\n FROM public.plg_inventory_stock_positions sp\n WHERE sp.tenant_id = p_tenant\n AND sp.product_id = v_product\n AND sp.stock_location_id = v_location\n AND sp.batch_number IS NOT DISTINCT FROM nullif(btrim(p_row ->> 'batch_number'), '')\n AND sp.expiration_date IS NOT DISTINCT FROM (p_row ->> 'expiration_date')::date\n LIMIT 1;\n END IF;\n ELSE\n v_target := v_movement;\n END IF;\n\n -- A porteira do inventário: a operação recusa UPDATE sem ela, do porte\n -- inclusive. Transacional, para não vazar para a linha seguinte.\n v_prev := coalesce(current_setting('fayz.inventory_internal', true), 'off');\n PERFORM set_config('fayz.inventory_internal', 'on', true);\n UPDATE public.plg_inventory_operations o\n SET result = coalesce(o.result, '{}'::jsonb) || jsonb_build_object(\n CASE WHEN v_part = 'batch' THEN 'batches' ELSE 'lines' END,\n coalesce(o.result -> CASE WHEN v_part = 'batch' THEN 'batches' ELSE 'lines' END, '{}'::jsonb)\n || jsonb_build_object(p_id::text, v_linha))\n WHERE o.id = v_operation AND o.tenant_id = p_tenant;\n PERFORM set_config('fayz.inventory_internal', v_prev, true);\n\n IF v_target IS NULL THEN\n -- Linha declarada e nunca conciliada: no V1 ela não virou estoque, e o\n -- porte não inventa a entrada que a origem não fez. O conteúdo dela já foi\n -- gravado no \\`result\\` acima — o que falta é só o vínculo com o razão.\n RETURN jsonb_build_object('status', 'skipped',\n 'reason', CASE WHEN v_part = 'batch'\n THEN 'lote sem posição no V2 — o movimento dele não atravessou'\n ELSE 'linha sem movimento no V1 — nunca virou estoque' END);\n END IF;\n\n IF v_standalone THEN\n PERFORM migration._audit(p_tenant,\n CASE WHEN v_part = 'batch' THEN 'public.plg_inventory_stock_positions'\n ELSE 'public.plg_inventory_stock_movements' END,\n v_target, jsonb_build_object('reason', 'adopted'));\n END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', v_target,\n 'reason', CASE WHEN v_part = 'batch'\n THEN 'a posição deste lote já é consequência do movimento'\n ELSE 'a linha é o movimento que já atravessou' END);\nEND $function$;\n\nCOMMENT ON FUNCTION migration.upsert_inv_danfe_line(uuid, uuid, jsonb, jsonb) IS\n 'A linha (ou o lote) da nota de entrada. Adota o movimento/posição que o V1 já '\n 'gerou em vez de criar um segundo — 94,7% das linhas do tenant 8 têm movimento, '\n 'e duplicá-lo dobraria o estoque — e guarda o conteúdo da linha em operations.result.';\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 4. O vocabulário de writers aceita os nomes novos\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- Lendo e costurando o CHECK que está lá, nunca reescrevendo com lista literal:\n-- a lista literal apaga as palavras que os outros passos da corrente\n-- acrescentaram, e o erro só aparece na onda seguinte.\n\nDO $$\nDECLARE v_def text;\nBEGIN\n SELECT pg_get_constraintdef(oid) INTO v_def\n FROM pg_constraint WHERE conname = 'allowlist_writer_check';\n IF v_def IS NULL OR strpos(v_def, 'inv_shape') > 0 THEN RETURN; END IF;\n ALTER TABLE migration.allowlist DROP CONSTRAINT allowlist_writer_check;\n EXECUTE replace(\n 'ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check ' || v_def,\n '''person''::text', '''person''::text, ''inv_shape''::text');\nEND $$;\n\nDO $$\nDECLARE v_def text;\nBEGIN\n SELECT pg_get_constraintdef(oid) INTO v_def\n FROM pg_constraint WHERE conname = 'allowlist_writer_check';\n IF v_def IS NULL OR strpos(v_def, 'inv_danfe_line') > 0 THEN RETURN; END IF;\n ALTER TABLE migration.allowlist DROP CONSTRAINT allowlist_writer_check;\n EXECUTE replace(\n 'ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check ' || v_def,\n '''person''::text', '''person''::text, ''inv_danfe_line''::text');\nEND $$;\n\n-- ─────────────────────────────────────────────────────────────────────────────\n-- 5. O de-para\n-- ─────────────────────────────────────────────────────────────────────────────\n--\n-- A ordem é a da dependência: a nota antes das linhas, as linhas antes dos\n-- lotes. As três resolvem \\`import_id@danfe_imports\\` pelo ledger, e o ledger só\n-- responde depois que a nota atravessou.\n\nSET LOCAL migration.allowlist_unlock = 'on';\n\nSELECT migration._allow(\n 'danfe_imports', 'public.plg_inventory_operations', 'inventory', 'inv_shape',\n jsonb_build_object('target', 'public.plg_inventory_operations'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n -- \\`kind\\` e \\`op_status\\` vêm do augment do extrator: o V1 não guarda a\n -- palavra \"receive\" porque a tabela INTEIRA é de entrada, e o status dele\n -- tem cinco palavras (pending | partial | stocked | conciliated |\n -- asset_registered) onde o V2 tem duas. Medido: 71 pendentes e 536\n -- concluídas nos dois tenants.\n 'kind', 'kind',\n 'op_status', 'status',\n 'access_key', 'idempotency_key',\n 'unit_id', 'unit_id@companies',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'status', 'jsonb:danfe.v1_status',\n 'nfe_number', 'jsonb:danfe.nfe_number',\n 'nfe_series', 'jsonb:danfe.nfe_series',\n 'issue_date', 'jsonb:danfe.issue_date',\n 'nature_operation', 'jsonb:danfe.nature_operation',\n 'supplier_name', 'jsonb:danfe.supplier.name',\n 'supplier_cnpj', 'jsonb:danfe.supplier.cnpj',\n 'supplier_id', 'jsonb:danfe.supplier.v1_ref',\n 'total_value', 'jsonb:danfe.totals.total',\n 'discount_value', 'jsonb:danfe.totals.discount',\n 'freight_value', 'jsonb:danfe.totals.freight',\n 'insurance_value', 'jsonb:danfe.totals.insurance',\n 'other_expenses', 'jsonb:danfe.totals.other',\n 'total_items', 'jsonb:danfe.total_items',\n 'conciliated_items', 'jsonb:danfe.conciliated_items',\n 'imported_by', 'jsonb:danfe.imported_by',\n 'payment_summary', 'jsonb:danfe.payment_summary',\n 'default_chart_account_id', 'jsonb:danfe.v1_default_chart_account_ref',\n 'id', 'jsonb:danfe.v1_ref'),\n 'A importação de DANFE é uma operação de RECEBIMENTO, e a idempotency_key '\n 'dela é a chave de acesso — 607 de 607 notas têm chave e ela é única no '\n 'tenant, então op.idempotency_key = doc.access_key liga a operação ao '\n 'documento fiscal sem FK entre plugins. O conteúdo fiscal não é copiado: as '\n '607 notas já estão em plg_fiscalbr_inbox_documents, com o mesmo número de '\n 'linhas em 607 de 607.'\n);\n\nSELECT migration._allow(\n 'danfe_import_items', 'public.plg_inventory_stock_movements', 'inventory', 'inv_danfe_line',\n jsonb_build_object('part', 'item'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'import_id', 'operation_id@danfe_imports',\n -- O movimento que ESTA linha gerou no V1. Resolve pelo ledger de\n -- \\`stock_movements\\`; nulo quando a linha nunca foi conciliada, e\n -- irresolvido (quarentena \\`fk\\`) quando o movimento existe e não atravessou.\n 'movement_uuid', 'movement_id@stock_movements',\n 'linked_product_id', 'product_id@products',\n 'item_number', 'line_no',\n 'created_at', 'created_at',\n 'tenant_id', '-',\n 'description', 'jsonb:danfe.line.description',\n 'product_code_supplier', 'jsonb:danfe.line.supplier_code',\n 'ean_barcode', 'jsonb:danfe.line.ean',\n 'ncm', 'jsonb:danfe.line.ncm',\n 'cfop', 'jsonb:danfe.line.cfop',\n 'quantity', 'jsonb:danfe.line.quantity',\n 'unit_abbreviation', 'jsonb:danfe.line.unit',\n 'unit_price', 'jsonb:danfe.line.unit_price',\n 'total_price', 'jsonb:danfe.line.total_price',\n 'icms_value', 'jsonb:danfe.line.icms_value',\n 'ipi_value', 'jsonb:danfe.line.ipi_value',\n 'pis_value', 'jsonb:danfe.line.pis_value',\n 'cofins_value', 'jsonb:danfe.line.cofins_value',\n 'entry_type', 'jsonb:danfe.line.entry_type',\n 'cst_entry', 'jsonb:danfe.line.cst_entry',\n 'chart_account_id', 'jsonb:danfe.line.v1_chart_account_ref',\n 'stock_unit_id', 'jsonb:danfe.line.v1_stock_unit_ref',\n 'stock_quantity', 'jsonb:danfe.line.stock_quantity',\n 'conversion_factor', 'jsonb:danfe.line.conversion_factor',\n 'cost_mode', 'jsonb:danfe.line.cost_mode',\n 'reconciled', 'jsonb:danfe.line.reconciled',\n 'xml_batches', 'jsonb:danfe.line.xml_batches',\n 'ai_suggested', 'jsonb:danfe.line.ai.suggested',\n 'ai_create_product', 'jsonb:danfe.line.ai.create_product',\n 'ai_product_name', 'jsonb:danfe.line.ai.product_name',\n 'ai_product_barcode', 'jsonb:danfe.line.ai.product_barcode',\n 'ai_product_cost_price', 'jsonb:danfe.line.ai.product_cost_price',\n 'ai_product_unit_id', 'jsonb:danfe.line.ai.v1_product_unit_ref',\n 'id', 'jsonb:danfe.line.v1_ref'),\n 'A linha da nota. NÃO cria movimento: 2.707 dos 2.860 itens do tenant 8 já '\n 'têm o movimento que o V1 gerou, e ele já atravessou — um segundo dobraria a '\n 'entrada e, pelo gatilho after_insert, o saldo junto. A linha adota aquele '\n 'movimento e guarda em operations.result o que ele não nomeia: fator de '\n 'conversão, conta contábil, CST de entrada e o produto sugerido pela IA.'\n);\n\nSELECT migration._allow(\n 'danfe_import_item_batches', 'public.plg_inventory_stock_positions', 'inventory', 'inv_danfe_line',\n jsonb_build_object('part', 'batch'),\n NULL::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'import_id', 'operation_id@danfe_imports',\n 'product_ref', 'product_id@products',\n 'stock_location_id', 'stock_location_id@stock_locations',\n 'stock_movement_uuid', 'movement_id@stock_movements',\n 'quantity', 'quantity',\n 'batch_number', 'batch_number',\n 'expiration_date', 'expiration_date',\n 'created_at', 'created_at',\n 'updated_at', 'updated_at',\n 'tenant_id', '-',\n 'item_id', 'jsonb:danfe.batch.v1_item_ref',\n 'received_at', 'jsonb:danfe.batch.received_at',\n 'received_by', 'jsonb:danfe.batch.v1_received_by',\n 'source', 'jsonb:danfe.batch.source',\n 'id', 'jsonb:danfe.batch.v1_ref'),\n 'O lote declarado na entrada — 66 no tenant 1 (todos do XML) e 2 no tenant 8 '\n '(manuais). Não desfaz a 005: a posição continua sendo consequência do '\n 'movimento e este de-para não grava nenhuma. O gatilho after_insert já criou '\n 'a posição com este lote e esta validade, e a linha do lote aponta para ela. '\n '32 dos 68 lotes têm movimento; os outros 36 ficam skipped, porque lote sem '\n 'movimento nunca foi saldo.'\n);\n\nDELETE FROM migration.excluded_tables\n WHERE source_table IN ('danfe_imports', 'danfe_import_items', 'danfe_import_item_batches');\n\nRESET migration.allowlist_unlock;\n\n\n-- ── quem pode executar ────────────────────────────────────────────────────\n--\n-- Função nova nasce executável por PUBLIC, e \\`anon\\`/\\`authenticated\\` herdam\n-- dali. Estas são de PORTE: SECURITY DEFINER, escrevem dados de qualquer\n-- inquilino, e uma delas alcançável pela chave anônima é a base inteira\n-- alcançável pela chave anônima. Só o service_role, que é quem roda a onda.\nREVOKE ALL ON FUNCTION migration.upsert_inv_shape(uuid, uuid, jsonb, jsonb) FROM PUBLIC, anon, authenticated;\nGRANT EXECUTE ON FUNCTION migration.upsert_inv_shape(uuid, uuid, jsonb, jsonb) TO service_role;\nREVOKE ALL ON FUNCTION migration.upsert_inv_danfe_line(uuid, uuid, jsonb, jsonb) FROM PUBLIC, anon, authenticated;\nGRANT EXECUTE ON FUNCTION migration.upsert_inv_danfe_line(uuid, uuid, jsonb, jsonb) TO service_role;\n`\n\nexport const MIGRATION_011_O_CONSUMO_TEM_DUAS_ORIGENS = `-- 011_o_consumo_tem_duas_origens.sql\n--\n-- A AUDITORIA DE USO ESTAVA VAZIA, E A CULPA NÃO ERA DELA.\n--\n-- A 001 leu o consumo no único lugar onde ele existia quando foi escrita: o\n-- razão, \\`plg_inventory_stock_movements\\` com \\`source_item_type='order_item'\\`.\n-- Isso pressupõe que consumir DEU BAIXA. É verdade para o consumo que nasce no\n-- V2 — \\`order.completed\\` consome a receita no mesmo instante — e é falso para\n-- tudo o que veio do V1.\n--\n-- O NÚMERO QUE OBRIGA ESTA MIGRATION. No V1, tenant 1:\n--\n-- execution_products ......................... 117.024 linhas\n-- stock_deducted = true ...................... 0\n-- stock_movement_id preenchido ............... 0\n--\n-- Zero. Em nenhum momento da história daquele banco o consumo declarado virou\n-- movimento de estoque — é exatamente o que os dois FLOW.md descrevem: no V1 a\n-- auditoria é um PORTÃO PRÉ-BAIXA, e a fila nunca foi drenada. Migrado, esse\n-- histórico chegou ao V2 como \\`plg_clinical_session_products\\` (116.911 linhas\n-- no Espaço Facial) e não produziu nenhum movimento, porque não havia nenhum\n-- para produzir.\n--\n-- Resultado medido no cluster, pelo papel \\`authenticated\\` com as claims do\n-- tenant: \\`v_inventory_consumption_audit\\` devolvia **0 linhas**. A tela do V2 é um\n-- porte fiel da do V1 — produto, quantidade com o «Padrão: N» só quando\n-- diverge, «Sem posição», data, profissional, cliente — e estava passando\n-- fome.\n--\n-- O QUE MUDA AQUI: o consumo passa a ter DUAS ORIGENS.\n--\n-- \\`ledger\\` — a baixa que realmente saiu do estoque (a 001, intacta).\n-- \\`clinical\\` — a declaração do atendimento que nunca virou baixa.\n--\n-- A PERGUNTA DA TELA É A MESMA NAS DUAS. «O que o profissional disse ter usado\n-- bate com o padrão?» não depende de o saldo ter mudado. O que muda é o que\n-- «corrigir» significa, e é por isso que a vista ganha \\`stock_posted\\`: na\n-- origem do razão corrigir DEVOLVE ao saldo; na origem clínica não há o que\n-- devolver, e corrigir é o mesmo ato do V1 — conserta a quantidade declarada e\n-- aprova.\n--\n-- POR QUE NÃO UMA FILA NOVA. Pelo mesmo motivo da 001: seria um segundo lugar\n-- guardando a mesma quantidade. \\`plg_clinical_session_products\\` JÁ é o registro\n-- do consumo declarado, com \\`default_quantity\\` (o «Padrão: N» do V1),\n-- \\`used_quantity\\`, \\`is_audited\\`, \\`audited_at\\` e \\`audit_notes\\`. A auditoria lê\n-- de onde o dado mora.\n--\n-- FORMA DA VISTA: as 29 colunas existentes continuam nas mesmas posições e com\n-- os MESMOS tipos — \\`variance\\` é \\`numeric\\` sem typmod, e um \\`numeric(14,4)\\` ali\n-- faria o \\`CREATE OR REPLACE\\` recusar. As duas colunas novas entram no fim, que\n-- é o único lugar onde o REPLACE aceita coluna nova. Nada de DROP: consultado o\n-- \\`pg_depend\\`, nada depende desta vista hoje, e mesmo assim um DROP CASCADE\n-- aqui seria o quarto acidente da casa.\n--\n-- \\`security_invoker\\` PRESERVADO. Sem ele a vista leria com os direitos de quem\n-- a criou e furaria a RLS das duas origens.\n--\n-- CONSEQUÊNCIA CONHECIDA, e ela é de propósito: com \\`security_invoker\\`, a\n-- origem clínica é filtrada pela policy de \\`plg_clinical_session_products\\`, que\n-- exige \\`clinical.read\\`. Um estoquista com \\`inventory.read\\` e sem\n-- \\`clinical.read\\` continua vendo a auditoria vazia. Alargar isso é decisão da\n-- policy do plugin clínico — dono da tabela —, não de uma migration do estoque,\n-- e escondê-la atrás de um \\`security_definer\\` seria trocar uma tela vazia por\n-- um vazamento.\n\n-- ── replay-safety ───────────────────────────────────────────────────────────\n--\n-- DROP before CREATE, and the reason is the rule this file exists under: the\n-- chain bench re-applies every migration on a populated database, and\n-- \\`CREATE OR REPLACE VIEW\\` may only APPEND columns — it refuses a narrower\n-- column list with \"cannot drop columns from view\". Files 012 through 018\n-- each widen this view, so on the second pass this statement would meet the\n-- final, wider shape and fail.\n--\n-- Dropping is free here and nowhere else: this view is born in this file. Its\n-- predecessor \\`v_inventory_usage_audit\\` (001, applied 2026-09-06) keeps its own\n-- name and its own narrow contract precisely so that it never has to be\n-- touched — an applied file with a changed checksum is a hard stop for\n-- \\`fayz db apply\\` on every cluster that already ran it.\nDROP VIEW IF EXISTS public.v_inventory_consumption_audit CASCADE;\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_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),\n\n-- ── origem 1: o consumo que saiu do estoque (a 001, sem uma vírgula a menos) ─\nledger AS (\n SELECT 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,\n (c.posted_quantity + coalesce(k.correction_delta, 0)) AS net_quantity,\n std.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)\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)) 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 'ledger'::text AS source,\n true AS stock_posted\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),\n\n-- ── origem 2: a declaração do atendimento que nunca virou baixa ─────────────\n--\n-- IDENTIDADE. A vista é chaveada por (item_id, produto), e 116.144 das 116.911\n-- linhas clínicas não têm \\`order_item_id\\` — o consumo do V1 pendurava na\n-- execução, não na linha vendida. Então \\`item_id\\` aqui é o \\`id\\` da PRÓPRIA\n-- linha clínica. Ela é única, é estável, é o que a tela usa como chave de linha\n-- e é por ela que a correção encontra o registro de volta.\n--\n-- O PADRÃO VEM DO V1, NÃO DA RECEITA. \\`default_quantity\\` é literalmente o\n-- «Padrão: N» que a tela do V1 mostrava — o número que estava cadastrado no\n-- serviço no dia do atendimento. Recalcular pela receita vigente do V2 seria\n-- comparar o passado com um padrão que ele não teve.\n--\n-- \\`nullif(default_quantity, 0)\\` NÃO É COSMÉTICO: 377 linhas vieram com padrão\n-- zero, que no V1 quer dizer «sem padrão cadastrado» (a tela testa\n-- \\`default_quantity > 0\\` antes de mostrar o selo). Sem o nullif, cada uma delas\n-- viraria uma divergência do valor inteiro e o filtro «só divergentes» passaria\n-- de 172 achados reais para 421 — afogar o achado é o mesmo que não ter achado.\nclinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n coalesce(cs.executed_on::timestamptz, cs.created_at) AS used_at,\n coalesce(cs.executed_on, cs.created_at::date) AS movement_date,\n -- Não houve postagem. «posted» aqui é o DECLARADO, e quem diz a verdade\n -- sobre o razão é \\`stock_posted = false\\`, logo abaixo. Igual ao V1,\n -- corrigir reescreve \\`used_quantity\\` no lugar, então declarado e\n -- líquido são sempre o mesmo número nesta origem.\n coalesce(cs.used_quantity, 0) AS posted_quantity,\n coalesce(cs.used_quantity, 0) AS net_quantity,\n nullif(cs.default_quantity, 0) AS standard_quantity,\n CASE WHEN nullif(cs.default_quantity, 0) IS NULL THEN NULL\n ELSE coalesce(cs.used_quantity, 0) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n -- custo zero não é «não sei»: é «nada saiu do estoque, logo nada\n -- custou ao estoque». Inventar aqui o preço de catálogo daria à tela\n -- um valor que nenhum razão jamais escreveu.\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n -- o V1 mostrava «Sem posição» em 117.024 de 117.024 linhas; a ausência\n -- de local aqui é o porte fiel daquele selo, não uma perda de dado\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n -- o V1 mostrava o SERVIÇO na linha; no V2 o serviço é um \\`products\\`\n sv.name AS item_name,\n o.reference_number AS order_reference,\n coalesce(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n -- «Corrigir» e «Aprovar» eram um ato só no V1: auditado é o conferido\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM public.plg_clinical_session_products cs\n LEFT JOIN public.plg_clinical_sessions s\n ON s.tenant_id = cs.tenant_id AND s.id = cs.session_id\n LEFT JOIN public.products p ON p.id = cs.product_id\n LEFT JOIN public.products sv ON sv.id = s.service_id\n LEFT JOIN public.plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN public.items i ON i.id = cs.order_item_id AND i.tenant_id = cs.tenant_id\n LEFT JOIN public.orders o ON o.id = i.order_id\n LEFT JOIN public.people perf ON perf.id = coalesce(cs.assignee_id, s.performed_by_id, s.assignee_id)\n LEFT JOIN public.people cust ON cust.id = s.party_id\n -- A MESMA LINHA NÃO CONTA DUAS VEZES. Se a declaração clínica já produziu\n -- uma saída no razão, quem manda é o razão: é ele que tem custo, posição e\n -- a correção que devolve saldo.\n --\n -- O teste de estorno NÃO se repete aqui de propósito. A 001 decidiu que\n -- saída estornada sai da fila; se o gêmeo clínico reaparecesse quando o\n -- estorno acontece, a mesma linha voltaria à conferência pela porta dos\n -- fundos e diria o contrário do que a 001 disse.\n WHERE NOT EXISTS (\n SELECT 1\n FROM public.plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id\n AND m.source_item_type = 'order_item'\n AND m.source_item_id = cs.order_item_id\n AND m.product_id = cs.product_id\n AND m.kind = 'out'\n )\n)\n\n-- O casco externo existe pelos TYPMODS. Um UNION apaga \\`numeric(14,4)\\` e deixa\n-- \\`numeric\\` puro, e o \\`CREATE OR REPLACE VIEW\\` recusa mudança de tipo de coluna\n-- existente — inclusive typmod. Então cada coluna volta ao tipo que ela já\n-- tinha, um a um. \\`variance\\` fica \\`numeric\\` SEM typmod porque é assim que ela\n-- está no catálogo hoje; apertá-la para \\`numeric(14,4)\\` seria o mesmo erro pelo\n-- lado oposto.\nSELECT a.tenant_id,\n a.unit_id,\n a.item_id,\n a.product_id,\n a.product_name,\n a.product_sku,\n a.used_at,\n a.movement_date,\n a.posted_quantity::numeric(14,4) AS posted_quantity,\n a.net_quantity::numeric(14,4) AS net_quantity,\n a.standard_quantity::numeric(14,4) AS standard_quantity,\n a.variance::numeric AS variance,\n a.unit_abbreviation,\n a.total_cost::numeric(16,4) AS total_cost,\n a.stock_location_id,\n a.stock_location_name,\n a.location_count,\n a.recipe_id,\n a.recipe_name,\n a.order_id,\n a.item_name,\n a.order_reference,\n a.performed_by_id,\n a.performed_by_name,\n a.customer_id,\n a.customer_name,\n a.corrected_at,\n a.correction_reason,\n a.is_corrected,\n -- ── colunas novas, no fim, que é onde o REPLACE aceita ──────────────\n a.source,\n a.stock_posted\n FROM (\n SELECT * FROM ledger\n UNION ALL\n SELECT * FROM clinical\n ) a;\n\nCOMMENT ON VIEW public.v_inventory_consumption_audit IS\n 'O consumo declarado em cada atendimento ao lado do padrão, por linha e produto, nas suas duas origens: o que saiu do razão (source=ledger) e o que o V1 declarou e nunca baixou (source=clinical, stock_posted=false). Não cria fila: os dois lugares já guardavam tudo (001, 011).';\n\nGRANT SELECT ON public.v_inventory_consumption_audit TO authenticated;\nGRANT SELECT ON public.v_inventory_consumption_audit TO service_role;\n\n-- ── índices: a conferência é sempre (tenant, mais recente primeiro) ─────────\n--\n-- A tela pagina 50 por vez ordenando por \\`used_at DESC\\` sobre 116.911 linhas.\n-- Sem isto a vista varre a tabela inteira a cada página.\nCREATE INDEX IF NOT EXISTS plg_clinical_session_products_audit_idx\n ON public.plg_clinical_session_products (tenant_id, executed_on DESC, id);\n\n-- O anti-join da deduplicação entra pelo par (linha vendida, produto)\nCREATE INDEX IF NOT EXISTS plg_clinical_session_products_order_item_idx\n ON public.plg_clinical_session_products (tenant_id, order_item_id, product_id)\n WHERE order_item_id IS NOT NULL;\n\n-- ───────────────────────────────────────────────────────────────────────────\n-- CORRIGIR, NA ORIGEM CLÍNICA\n--\n-- A 002 fez de \\`app.inventory_correct_usage_line\\` o miolo único: a correção\n-- avulsa e o lote são o mesmo código. Ele procura a baixa no razão e, não\n-- achando, levanta «no usage of product % on item % to correct». Com a vista\n-- servindo 116.890 linhas clínicas, esse erro passaria a ser a resposta normal\n-- da tela — o botão existiria só para falhar.\n--\n-- O QUE CORRIGIR SIGNIFICA EM CADA ORIGEM:\n--\n-- razão — a baixa aconteceu; corrigir 50 para 40 DEVOLVE 10 ao saldo, como\n-- ajuste, porque o razão é append-only. (inalterado)\n-- clínica — nada saiu; não há o que devolver. Corrigir é o ato do V1:\n-- conserta a quantidade declarada, exige motivo, e APROVA junto —\n-- «Salvar e Aprovar» era um botão só, nunca dois.\n--\n-- Lançar um ajuste de estoque para a origem clínica seria pior que não\n-- corrigir: criaria movimento para um consumo que nunca teve movimento, e o\n-- saldo passaria a contar uma devolução de algo que nunca saiu.\n--\n-- PERMISSÃO, EXPLICITAMENTE. A função é SECURITY DEFINER, então o UPDATE não\n-- passa pela RLS de \\`plg_clinical_session_products\\` — quem tem de barrar é este\n-- código. Exige-se \\`inventory.edit\\` na unidade do consumo, que é a mesma regra\n-- do caminho do razão (\\`inventory_authorize_location\\` cobra \\`inventory.edit\\` na\n-- unidade do local). Linha sem unidade (906 delas) cai no teste «em qualquer\n-- unidade», espelhando o \\`unit_id IS NULL OR has_unit(...)\\` da própria policy.\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_cs 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 -- ── a origem clínica: consumo declarado que nunca virou baixa ────────────\n IF v_row.net IS NULL THEN\n SELECT cs.id, cs.unit_id, cs.used_quantity, cs.is_audited\n INTO v_cs\n FROM public.plg_clinical_session_products cs\n WHERE cs.tenant_id = p_tenant\n AND cs.id = p_item_id\n AND cs.product_id = p_product_id;\n\n IF v_cs.id 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 IF v_cs.unit_id IS NOT NULL THEN\n IF NOT app.has_unit(v_cs.unit_id) THEN\n RAISE EXCEPTION 'inventory: no access to the unit of usage %', p_item_id USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('inventory.edit', v_cs.unit_id) THEN\n RAISE EXCEPTION 'inventory: inventory.edit required at the unit of usage %', p_item_id\n USING ERRCODE = '42501';\n END IF;\n ELSIF NOT app.has_permission_anywhere('inventory.edit') THEN\n RAISE EXCEPTION 'inventory: inventory.edit required to correct usage %', p_item_id\n USING ERRCODE = '42501';\n END IF;\n\n -- Conferir e não mudar número AINDA é conferir: a linha pendente vira\n -- auditada. Só é «unchanged» o que já estava auditado com este número —\n -- reenviar o mesmo lote não reescreve a data da auditoria.\n IF coalesce(v_cs.used_quantity, 0) = p_quantity AND v_cs.is_audited THEN\n RETURN jsonb_build_object('status', 'unchanged', 'origin', 'clinical',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'previous_quantity', coalesce(v_cs.used_quantity, 0),\n 'quantity', p_quantity, 'delta', 0);\n END IF;\n\n UPDATE public.plg_clinical_session_products\n SET used_quantity = p_quantity,\n is_audited = true,\n audited_at = now(),\n audited_by = auth.uid(),\n audit_notes = p_reason,\n updated_at = now()\n WHERE tenant_id = p_tenant AND id = p_item_id AND product_id = p_product_id;\n\n -- Sem \\`movements\\`: nada entrou no razão, e devolver uma lista vazia é o que\n -- diz isso a quem chamou. O lote continua contando a linha como aplicada.\n RETURN jsonb_build_object('status', 'corrected', 'origin', 'clinical',\n 'item_id', p_item_id, 'product_id', p_product_id,\n 'unit_id', v_cs.unit_id,\n 'previous_quantity', coalesce(v_cs.used_quantity, 0),\n 'quantity', p_quantity,\n 'delta', coalesce(v_cs.used_quantity, 0) - p_quantity,\n 'movements', '[]'::jsonb);\n END IF;\n\n -- ── a origem do razão: inalterada desde a 002 ────────────────────────────\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', 'origin', 'ledger', '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', 'origin', 'ledger', '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. Origem razão: lança a diferença como ajuste. Origem clínica (consumo do V1 que nunca baixou): conserta a quantidade declarada e aprova, sem tocar no saldo (002, 011).';\n\nREVOKE ALL ON FUNCTION app.inventory_correct_usage_line(uuid, uuid, text, integer, uuid, uuid, numeric, text) FROM PUBLIC;\n`\n\nexport const MIGRATION_012_O_CONSUMO_CLINICO_NAO_PRECISA_DA_TABELA_DE_ITENS_INTEIRA = `-- O consumo clínico não precisa da tabela de itens inteira.\n--\n-- A auditoria de uso continuava estourando o \\`statement_timeout\\` do papel\n-- \\`authenticated\\` (8 s) mesmo depois de a clinical/003 baratear a política. O\n-- plano, lido com o tempo solto, mostrou onde:\n--\n-- Hash (cost=154686.67 rows=23255) (actual rows=455925)\n--\n-- O ramo clínico da vista faz \\`LEFT JOIN items i ON i.id = cs.order_item_id\\`, e\n-- o planejador resolve isso montando um hash de \\`public.items\\` INTEIRA —\n-- 455.925 linhas — para casar com 116.911 consumos. Só que **767** desses\n-- consumos têm \\`order_item_id\\`: no V1 o produto usado pendura na execução, não\n-- na linha vendida. O hash existe para 0,7% das linhas e é pago por 100%.\n--\n-- O mesmo vale para \\`orders\\` e para as duas idas a \\`people\\` (120.808 linhas\n-- cada uma, uma para quem executou e outra para a cliente).\n--\n-- ── A correção é a forma do join, não o dado ────────────────────────────────\n--\n-- Cada um vira LATERAL com a condição de existência dentro. Assim o planejador\n-- deixa de montar hash e passa a fazer busca por chave primária — 767 buscas em\n-- vez de um hash de 455 mil linhas —, e as linhas sem \\`order_item_id\\` não\n-- procuram nada.\n--\n-- \\`LEFT JOIN LATERAL ... ON true\\` preserva a semântica do LEFT JOIN: a linha do\n-- consumo sobrevive mesmo quando não há item, que é o caso de 116.144 delas.\n--\n-- Medido no cluster, como o usuário que estava com a tela aberta, com ROLLBACK:\n--\n-- 50 linhas ordenadas por data 1,94 s (antes: estourava os 8 s)\n-- contagem total 1,27 s 116.911 linhas — a MESMA de antes\n--\n-- A contagem idêntica é o teste que importa: uma vista que fica rápida\n-- devolvendo menos linha não ficou rápida, ficou errada.\n--\n-- Idempotente. \\`CREATE OR REPLACE\\` mantém nome, ordem e tipo das colunas — só\n-- os joins mudam — e mantém \\`security_invoker\\`, sem o qual a vista passaria a\n-- ler com os direitos de quem a criou e furaria a RLS.\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n COALESCE(cs.executed_on::timestamp with time zone, cs.created_at) AS used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN plg_clinical_sessions s ON s.tenant_id = cs.tenant_id AND s.id = cs.session_id\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id) o ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id)) perf ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = s.party_id) cust ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_013_A_FILA_DE_AUDITORIA_TEM_UMA_JANELA = `-- A fila de auditoria tem uma janela, e a janela precisa de índice.\n--\n-- \\`v_inventory_consumption_audit\\` atravessa a história inteira do consumo. No Espaço\n-- Facial isso é 116.939 linhas, e pedir as 50 mais recentes custava 7 s de\n-- banco: a tela voltava \\`canceling statement due to statement timeout\\` e, pior,\n-- mostrava \"Nenhum consumo fora do padrão\" por cima do erro.\n--\n-- A tela passou a pedir uma janela (\\`used_at >= agora - 30 dias\\`), mas o ramo\n-- clínico não tinha como responder por ela: \\`used_at\\` é\n-- \\`coalesce(executed_on::timestamptz, created_at)\\` e essa expressão NÃO é\n-- indexável — o cast de \\`date\\` para \\`timestamptz\\` depende do fuso da sessão e\n-- o Postgres o recusa em índice.\n--\n-- \\`timezone('UTC', executed_on::timestamp)\\` é o MESMO valor (o cluster roda em\n-- UTC) e é imutável. Trocada a expressão, o índice abaixo existe e a janela\n-- deixa de ser uma varredura.\n\nCREATE INDEX IF NOT EXISTS plg_clinical_session_products_used_at_idx\n ON public.plg_clinical_session_products (\n tenant_id,\n (COALESCE(timezone('UTC', executed_on::timestamp), created_at)) DESC\n );\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n COALESCE(timezone('UTC', cs.executed_on::timestamp), cs.created_at) AS used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN plg_clinical_sessions s ON s.tenant_id = cs.tenant_id AND s.id = cs.session_id\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id) o ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id)) perf ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = s.party_id) cust ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_014_A_SESSAO_SE_BUSCA_UMA_A_UMA = `-- O atendimento entra na fila UM A UM, não a tabela inteira.\n--\n-- A vista buscava a sessão de cada consumo com um LEFT JOIN comum. Sob RLS\n-- isso é caro de um jeito que não aparece no EXPLAIN de quem tem chave de\n-- serviço: a política de \\`plg_clinical_sessions\\` chama \\`app.has_unit\\` e\n-- \\`app.has_permission\\` POR LINHA, e o planejador varre a tabela inteira antes\n-- de casar com os poucos consumos da janela. Medido aqui: 232.264 chamadas,\n-- 6,4 s — e a tela voltava \\`canceling statement due to statement timeout\\` com\n-- a janela de 30 dias já aplicada.\n--\n-- LATERAL amarra a busca à linha de fora: a sessão é procurada pela chave\n-- (tenant, id) uma vez por consumo, e a RLS roda dezenas de vezes em vez de\n-- centenas de milhares. É a mesma correção que a 012 já tinha feito para\n-- \\`items\\`, \\`orders\\` e \\`people\\` — a sessão tinha ficado de fora.\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n COALESCE(timezone('UTC', cs.executed_on::timestamp), cs.created_at) AS used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN LATERAL ( SELECT ss.party_id, ss.performed_by_id, ss.assignee_id, ss.service_id\n FROM plg_clinical_sessions ss\n WHERE ss.tenant_id = cs.tenant_id AND ss.id = cs.session_id) s ON true\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id) o ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id)) perf ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = s.party_id) cust ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_015_LATERAL_SEM_CERCA_NAO_E_LATERAL = `-- LATERAL sem cerca não é LATERAL.\n--\n-- A 012 e a 014 escreveram as buscas de \\`items\\`, \\`orders\\`, \\`people\\` e da\n-- sessão como LATERAL para que cada uma rodasse por linha. O planejador\n-- desfez o gesto: subconsulta simples é ACHATADA de volta a junção comum, e o\n-- plano voltava a varrer \\`people\\` inteira (61.854 linhas) e a sessão inteira.\n-- Sob RLS cada uma dessas linhas paga \\`app.has_unit\\` + \\`app.has_permission\\`,\n-- e a tela morria nos 8 s do PostgREST.\n--\n-- \\`LIMIT 1\\` é a cerca: o Postgres não achata subconsulta com limite. A chave\n-- é única nos quatro casos, então o limite não muda resultado nenhum — só\n-- impede que a busca de UMA linha vire uma varredura de todas.\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n COALESCE(timezone('UTC', cs.executed_on::timestamp), cs.created_at) AS used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN LATERAL ( SELECT ss.party_id, ss.performed_by_id, ss.assignee_id, ss.service_id\n FROM plg_clinical_sessions ss\n WHERE ss.tenant_id = cs.tenant_id AND ss.id = cs.session_id LIMIT 1) s ON true\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id LIMIT 1) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id LIMIT 1) o ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) LIMIT 1) perf ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = s.party_id LIMIT 1) cust ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_016_A_DATA_DO_CONSUMO_E_UMA_COLUNA = `-- A data do consumo passa a ser uma COLUNA, e por isso a janela usa índice.\n--\n-- Sob RLS o Postgres roda as regras da política ANTES das condições de quem\n-- pergunta — a não ser que a condição seja \\`leakproof\\`. A janela da fila\n-- (\\`used_at >= agora - 30 dias\\`) era uma EXPRESSÃO com \\`timezone()\\`, que não é\n-- leakproof: o índice da 013 existia e o plano o ignorava, varrendo as 116.934\n-- linhas e chamando \\`app.has_unit\\` 116.028 vezes. Medido: 7,9 s, e a tela\n-- morria nos 8 s do PostgREST.\n--\n-- Coluna gerada e gravada resolve pela raiz: a comparação vira \\`coluna >=\n-- constante\\`, que é leakproof, entra como condição de índice e a RLS passa a\n-- rodar sobre as dezenas de linhas da janela em vez da tabela inteira. O valor\n-- é o mesmo de antes (o cluster roda em UTC), calculado uma vez na escrita.\n\nALTER TABLE public.plg_clinical_session_products\n ADD COLUMN IF NOT EXISTS used_at timestamptz\n GENERATED ALWAYS AS (COALESCE(timezone('UTC', executed_on::timestamp), created_at)) STORED;\n\nDROP INDEX IF EXISTS public.plg_clinical_session_products_used_at_idx;\nCREATE INDEX IF NOT EXISTS plg_clinical_session_products_used_at_idx\n ON public.plg_clinical_session_products (tenant_id, used_at DESC);\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n cs.used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n perf.name AS performed_by_name,\n s.party_id AS customer_id,\n cust.name AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN LATERAL ( SELECT ss.party_id, ss.performed_by_id, ss.assignee_id, ss.service_id\n FROM plg_clinical_sessions ss\n WHERE ss.tenant_id = cs.tenant_id AND ss.id = cs.session_id LIMIT 1) s ON true\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id LIMIT 1) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id LIMIT 1) o ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) LIMIT 1) perf ON true\n LEFT JOIN LATERAL ( SELECT pe.id, pe.name\n FROM people pe\n WHERE pe.id = s.party_id LIMIT 1) cust ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_017_APROVAR_E_BAIXAR_SAO_DOIS_GESTOS = `-- Aprovar e baixar no estoque são DOIS gestos, e faltavam os dois.\n--\n-- A fila da Auditoria de Uso existe desde o começo deste porte: o injetor\n-- lança o que usou, a linha chega aqui, e o estoquista confere. Só que a tela\n-- só sabia CORRIGIR a quantidade — não havia como aceitar. O consumo entrava\n-- na fila e o saldo nunca caía. A pergunta que a jornada 4 do V1 responde\n-- (\"executei e o estoque não mudou\") continuava sem resposta, porque o botão\n-- que a responde não existia.\n--\n-- O V1 tem três ações por linha, e elas são diferentes de propósito:\n--\n-- 📍 Baixar no estoque aceita E desconta do saldo\n-- ✏️ Corrigir conserta a quantidade digitada errada\n-- ✅ Aprovar aceita o consumo, sem mexer no saldo\n--\n-- \"Aprovar\" sem baixar existe para o consumo que não sai do estoque da casa —\n-- produto do próprio cliente, amostra do fornecedor, item já baixado por fora.\n--\n-- SOBRE SALDO NEGATIVO. Esta função NÃO exige saldo. O movimento é o registro\n-- do que foi usado numa pessoa, e isso aconteceu independentemente do que o\n-- sistema achava que havia na prateleira. Recusar a baixa por falta de saldo\n-- esconderia o consumo e deixaria a diferença invisível; deixar o saldo ficar\n-- negativo é exatamente o sinal que o estoquista precisa ver.\n\nCREATE OR REPLACE FUNCTION public.inventory_approve_usage_batch(\n p_lines jsonb,\n p_post boolean DEFAULT false,\n p_reason text DEFAULT NULL\n)\nRETURNS jsonb\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path TO ''\nAS $fn$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_actor uuid := auth.uid();\n v_key text;\n v_op record;\n r record;\n v_cs record;\n v_location uuid;\n v_cost numeric;\n v_movement uuid;\n v_no integer := 0;\n v_aprovadas integer := 0;\n v_baixadas integer := 0;\n v_puladas integer := 0;\n v_movements jsonb := '[]'::jsonb;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n\n SELECT 'usage_audit_approve:' || CASE WHEN p_post THEN 'post:' ELSE 'ack:' END\n || md5(string_agg((l->>'item_id'), ',' ORDER BY (l->>'item_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 -- \\`confirm\\` é a operação de quem TIRA do estoque por consumo — o mesmo\n -- verbo que o consumo de item de pedido usa. 'out' não existe no catálogo\n -- de operações (só de movimentos), e o CHECK recusava.\n v_tenant, CASE WHEN p_post THEN 'confirm' ELSE 'adjust' END, v_key,\n jsonb_build_object('source', 'usage_audit_approve', 'post', p_post, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR r IN\n SELECT (l->>'item_id')::uuid AS item_id, ord\n FROM jsonb_array_elements(p_lines) WITH ORDINALITY AS t(l, ord)\n ORDER BY ord\n LOOP\n v_no := v_no + 1;\n\n SELECT cs.* INTO v_cs\n FROM public.plg_clinical_session_products cs\n WHERE cs.tenant_id = v_tenant AND cs.id = r.item_id\n FOR UPDATE;\n\n -- Linha que não é consumo clínico já nasceu como movimento do razão: ela\n -- não tem o que aprovar, e some da fila por outro caminho.\n IF NOT FOUND THEN\n v_puladas := v_puladas + 1;\n CONTINUE;\n END IF;\n\n IF p_post AND coalesce(v_cs.used_quantity, 0) > 0 THEN\n -- ONDE A BAIXA ACONTECE. Preferência: o local padrão do produto na\n -- unidade, depois o da ficha, depois o primeiro local ativo dela.\n SELECT candidate.location_id INTO v_location\n FROM (\n SELECT s.default_location_id AS location_id,\n CASE WHEN v_cs.unit_id IS NOT NULL AND s.unit_id = v_cs.unit_id THEN 1 ELSE 2 END AS priority\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = v_tenant\n AND s.product_id = v_cs.product_id\n AND s.default_location_id IS NOT NULL\n AND (s.unit_id IS NULL OR s.unit_id = v_cs.unit_id)\n UNION ALL\n SELECT d.default_location_id, 3\n FROM public.plg_inventory_product_details d\n WHERE d.tenant_id = v_tenant\n AND d.product_id = v_cs.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 = v_tenant AND l.is_active\n ) candidate\n JOIN public.plg_inventory_stock_locations l\n ON l.id = candidate.location_id AND l.tenant_id = v_tenant AND l.is_active\n WHERE v_cs.unit_id IS NULL OR l.unit_id = v_cs.unit_id OR l.unit_id IS NULL\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: nenhum local de estoque ativo para a unidade deste consumo'\n USING ERRCODE = '22023';\n END IF;\n\n SELECT p.unit_cost INTO v_cost\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_cs.product_id\n AND p.stock_location_id = v_location\n ORDER BY p.expiration_date NULLS LAST, p.created_at\n LIMIT 1;\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, unit_id, product_id, kind, quantity, unit_cost, source_location_id,\n measurement_unit_id, document_type, document_number,\n source_item_type, source_item_id, idempotency_key, line_no, operation_id,\n user_id, metadata)\n VALUES\n (v_tenant, v_cs.unit_id, v_cs.product_id, 'out', -v_cs.used_quantity,\n coalesce(v_cost, 0), v_location, v_cs.used_unit_id, 'consumption',\n coalesce(v_cs.session_id::text, v_cs.id::text),\n 'usage_audit', v_cs.id, v_key, v_no, v_op.op_id, v_actor,\n jsonb_strip_nulls(jsonb_build_object(\n 'source', 'usage_audit_approve',\n 'session_id', v_cs.session_id,\n 'order_item_id', v_cs.order_item_id,\n 'reason', nullif(btrim(p_reason), ''))))\n RETURNING id INTO v_movement;\n\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n v_baixadas := v_baixadas + 1;\n END IF;\n\n -- CONFERIDO é o mesmo carimbo nos dois gestos: o que sai da fila é o que\n -- alguém olhou, tenha ou não baixado.\n UPDATE public.plg_clinical_session_products cs\n SET is_audited = true,\n audited_at = now(),\n audited_by = coalesce(cs.audited_by, v_actor),\n audit_notes = coalesce(nullif(btrim(p_reason), ''), cs.audit_notes),\n updated_at = now()\n WHERE cs.id = v_cs.id;\n v_aprovadas := v_aprovadas + 1;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, CASE WHEN p_post THEN 'confirm' ELSE 'adjust' END, v_key,\n jsonb_build_object(\n 'operation_id', v_op.op_id, 'kind', 'usage_audit_approve',\n 'idempotency_key', v_key, 'status', CASE WHEN p_post THEN 'posted' ELSE 'approved' END,\n 'lines_approved', v_aprovadas, 'lines_posted', v_baixadas,\n 'lines_skipped', v_puladas, 'movements', v_movements),\n jsonb_build_object('source', 'usage_audit_approve', 'post', p_post,\n 'lines_approved', v_aprovadas, 'lines_posted', v_baixadas));\nEND $fn$;\n\nGRANT EXECUTE ON FUNCTION public.inventory_approve_usage_batch(jsonb, boolean, text) TO authenticated;\n`\n\nexport const MIGRATION_018_O_NOME_NAO_SAI_DA_VISTA = `-- O NOME NÃO SAI DA VISTA. A vista devolve o id; quem pinta busca o nome.\n--\n-- \\`people\\` tem 120.379 linhas neste tenant e uma política de RLS que passa por\n-- \\`resource_grants\\`. Buscar o nome do profissional e o da cliente DENTRO da\n-- vista fazia essa política rodar linha a linha: a mesma consulta que custa\n-- 9 ms com chave de serviço levava **30 segundos** com a sessão de quem usa a\n-- tela, e o PostgREST desistia aos 8.\n--\n-- Nenhum índice conserta isso, porque o problema não é achar a pessoa — é a\n-- política ser avaliada uma vez por candidato. A saída é não perguntar ali: a\n-- vista entrega \\`performed_by_id\\` e \\`customer_id\\`, e a tela busca os ~50 nomes\n-- de uma vez, numa consulta só, com a RLS rodando uma vez para todos.\n\nCREATE OR REPLACE VIEW public.v_inventory_consumption_audit WITH (security_invoker = true) AS\n WITH consumed AS (\n SELECT m.tenant_id,\n m.unit_id,\n m.source_item_id AS item_id,\n m.product_id,\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)::integer 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'::text ORDER BY m.created_at, m.id))[1] AS recipe_id\n FROM plg_inventory_stock_movements m\n WHERE m.source_item_type = 'order_item'::text AND m.source_item_id IS NOT NULL AND m.kind = 'out'::text AND NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements r\n WHERE r.reverses_movement_id = m.id))\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 sum(- c.quantity) AS correction_delta,\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 plg_inventory_stock_movements c\n WHERE c.source_item_type = 'usage_audit'::text AND c.source_item_id IS NOT NULL\n GROUP BY c.tenant_id, c.source_item_id, c.product_id\n ), ledger AS (\n SELECT 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,\n c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) AS net_quantity,\n std.standard_quantity,\n CASE\n WHEN std.standard_quantity IS NULL THEN NULL::numeric\n ELSE c.posted_quantity + COALESCE(k.correction_delta, 0::numeric) - std.standard_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n c.total_cost + COALESCE(k.correction_cost, 0::numeric) AS total_cost,\n c.stock_location_id,\n sl.name AS stock_location_name,\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 NULL::text AS performed_by_name,\n o.party_id AS customer_id,\n NULL::text AS customer_name,\n k.corrected_at,\n k.correction_reason,\n k.item_id IS NOT NULL AS is_corrected,\n 'ledger'::text AS source,\n true AS stock_posted\n FROM consumed c\n LEFT JOIN corrected k ON k.tenant_id = c.tenant_id AND k.item_id = c.item_id AND k.product_id = c.product_id\n LEFT JOIN products p ON p.id = c.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = c.stock_location_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = c.measurement_unit_id\n LEFT JOIN items i ON i.id = c.item_id AND i.tenant_id = c.tenant_id\n LEFT JOIN orders o ON o.id = i.order_id\n LEFT JOIN people perf ON perf.id = i.assignee_id\n LEFT JOIN people cust ON cust.id = o.party_id\n LEFT JOIN plg_inventory_recipes r ON r.id = NULLIF(c.recipe_id, ''::text)::uuid AND r.tenant_id = c.tenant_id\n LEFT JOIN LATERAL ( SELECT\n CASE\n WHEN r.id IS NOT NULL AND COALESCE(r.yield_quantity, 0::numeric) > 0::numeric THEN ( SELECT round(sum(ri.quantity) * COALESCE(i.quantity, 1::numeric) / r.yield_quantity, 4) AS round\n FROM plg_inventory_recipe_ingredients ri\n WHERE ri.tenant_id = c.tenant_id AND ri.recipe_id = r.id AND ri.product_id = c.product_id)\n WHEN r.id IS NULL THEN i.quantity\n ELSE NULL::numeric\n END AS standard_quantity) std ON true\n ), clinical AS (\n SELECT cs.tenant_id,\n cs.unit_id,\n cs.id AS item_id,\n cs.product_id,\n p.name AS product_name,\n p.sku AS product_sku,\n cs.used_at,\n COALESCE(cs.executed_on, cs.created_at::date) AS movement_date,\n COALESCE(cs.used_quantity, 0::numeric) AS posted_quantity,\n COALESCE(cs.used_quantity, 0::numeric) AS net_quantity,\n NULLIF(cs.default_quantity, 0::numeric) AS standard_quantity,\n CASE\n WHEN NULLIF(cs.default_quantity, 0::numeric) IS NULL THEN NULL::numeric\n ELSE COALESCE(cs.used_quantity, 0::numeric) - cs.default_quantity\n END AS variance,\n u.abbreviation AS unit_abbreviation,\n 0::numeric AS total_cost,\n NULL::uuid AS stock_location_id,\n NULL::text AS stock_location_name,\n 1 AS location_count,\n NULL::uuid AS recipe_id,\n NULL::text AS recipe_name,\n i.order_id,\n sv.name AS item_name,\n o.reference_number AS order_reference,\n COALESCE(cs.assignee_id, s.performed_by_id, s.assignee_id) AS performed_by_id,\n NULL::text AS performed_by_name,\n s.party_id AS customer_id,\n NULL::text AS customer_name,\n cs.audited_at AS corrected_at,\n cs.audit_notes AS correction_reason,\n cs.is_audited AS is_corrected,\n 'clinical'::text AS source,\n false AS stock_posted\n FROM plg_clinical_session_products cs\n LEFT JOIN LATERAL ( SELECT ss.party_id, ss.performed_by_id, ss.assignee_id, ss.service_id\n FROM plg_clinical_sessions ss\n WHERE ss.tenant_id = cs.tenant_id AND ss.id = cs.session_id LIMIT 1) s ON true\n LEFT JOIN products p ON p.id = cs.product_id\n LEFT JOIN products sv ON sv.id = s.service_id\n LEFT JOIN plg_inventory_measurement_units u ON u.id = cs.used_unit_id\n LEFT JOIN LATERAL ( SELECT it.id, it.order_id, it.name, it.assignee_id\n FROM items it\n WHERE cs.order_item_id IS NOT NULL\n AND it.id = cs.order_item_id AND it.tenant_id = cs.tenant_id LIMIT 1) i ON true\n LEFT JOIN LATERAL ( SELECT ord.id, ord.reference_number, ord.party_id\n FROM orders ord\n WHERE i.order_id IS NOT NULL AND ord.id = i.order_id LIMIT 1) o ON true\n WHERE NOT (EXISTS ( SELECT 1\n FROM plg_inventory_stock_movements m\n WHERE m.tenant_id = cs.tenant_id AND m.source_item_type = 'order_item'::text AND m.source_item_id = cs.order_item_id AND m.product_id = cs.product_id AND m.kind = 'out'::text))\n )\n SELECT tenant_id,\n unit_id,\n item_id,\n product_id,\n product_name,\n product_sku,\n used_at,\n movement_date,\n posted_quantity::numeric(14,4) AS posted_quantity,\n net_quantity::numeric(14,4) AS net_quantity,\n standard_quantity::numeric(14,4) AS standard_quantity,\n variance,\n unit_abbreviation,\n total_cost::numeric(16,4) AS total_cost,\n stock_location_id,\n stock_location_name,\n location_count,\n recipe_id,\n recipe_name,\n order_id,\n item_name,\n order_reference,\n performed_by_id,\n performed_by_name,\n customer_id,\n customer_name,\n corrected_at,\n correction_reason,\n is_corrected,\n source,\n stock_posted\n FROM ( SELECT ledger.tenant_id,\n ledger.unit_id,\n ledger.item_id,\n ledger.product_id,\n ledger.product_name,\n ledger.product_sku,\n ledger.used_at,\n ledger.movement_date,\n ledger.posted_quantity,\n ledger.net_quantity,\n ledger.standard_quantity,\n ledger.variance,\n ledger.unit_abbreviation,\n ledger.total_cost,\n ledger.stock_location_id,\n ledger.stock_location_name,\n ledger.location_count,\n ledger.recipe_id,\n ledger.recipe_name,\n ledger.order_id,\n ledger.item_name,\n ledger.order_reference,\n ledger.performed_by_id,\n ledger.performed_by_name,\n ledger.customer_id,\n ledger.customer_name,\n ledger.corrected_at,\n ledger.correction_reason,\n ledger.is_corrected,\n ledger.source,\n ledger.stock_posted\n FROM ledger\n UNION ALL\n SELECT clinical.tenant_id,\n clinical.unit_id,\n clinical.item_id,\n clinical.product_id,\n clinical.product_name,\n clinical.product_sku,\n clinical.used_at,\n clinical.movement_date,\n clinical.posted_quantity,\n clinical.net_quantity,\n clinical.standard_quantity,\n clinical.variance,\n clinical.unit_abbreviation,\n clinical.total_cost,\n clinical.stock_location_id,\n clinical.stock_location_name,\n clinical.location_count,\n clinical.recipe_id,\n clinical.recipe_name,\n clinical.order_id,\n clinical.item_name,\n clinical.order_reference,\n clinical.performed_by_id,\n clinical.performed_by_name,\n clinical.customer_id,\n clinical.customer_name,\n clinical.corrected_at,\n clinical.correction_reason,\n clinical.is_corrected,\n clinical.source,\n clinical.stock_posted\n FROM clinical) a;;\n`\n\nexport const MIGRATION_019_SEM_SALDO_NAO_SE_BAIXA = `-- Sem saldo não se baixa — e a fila diz qual produto faltou.\n--\n-- A 017 assumiu que a baixa sempre cabe. Não cabe: o gatilho de posição da\n-- plataforma recusa saída sem lastro, e o estoque deste tenant está zerado em\n-- 223 dos 225 produtos. O clique voltava com o erro cru do Postgres\n-- (\"insufficient stock (no position for product …)\") e a linha sumia do\n-- alcance de quem tentou.\n--\n-- Agora a linha sem saldo é SEPARADA: não é baixada, não é carimbada como\n-- conferida — continua pendente, que é o estado certo enquanto a entrada não\n-- for dada —, e volta com nome de produto, quanto precisa e quanto há.\n\nCREATE OR REPLACE FUNCTION public.inventory_approve_usage_batch(\n p_lines jsonb,\n p_post boolean DEFAULT false,\n p_reason text DEFAULT NULL\n)\nRETURNS jsonb\nLANGUAGE plpgsql\nSECURITY DEFINER\nSET search_path TO ''\nAS $fn$\nDECLARE\n v_tenant uuid := app.inventory_require_tenant();\n v_actor uuid := auth.uid();\n v_key text;\n v_op record;\n r record;\n v_cs record;\n v_location uuid;\n v_cost numeric;\n v_movement uuid;\n v_no integer := 0;\n v_aprovadas integer := 0;\n v_baixadas integer := 0;\n v_puladas integer := 0;\n v_sem_saldo integer := 0;\n v_faltando jsonb := '[]'::jsonb;\n v_disp numeric;\n v_movements jsonb := '[]'::jsonb;\nBEGIN\n PERFORM app.inventory_check_lines(p_lines);\n\n SELECT 'usage_audit_approve:' || CASE WHEN p_post THEN 'post:' ELSE 'ack:' END\n || md5(string_agg((l->>'item_id'), ',' ORDER BY (l->>'item_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 -- \\`confirm\\` é a operação de quem TIRA do estoque por consumo — o mesmo\n -- verbo que o consumo de item de pedido usa. 'out' não existe no catálogo\n -- de operações (só de movimentos), e o CHECK recusava.\n v_tenant, CASE WHEN p_post THEN 'confirm' ELSE 'adjust' END, v_key,\n jsonb_build_object('source', 'usage_audit_approve', 'post', p_post, 'lines', p_lines));\n IF v_op.existing IS NOT NULL THEN\n RETURN v_op.existing;\n END IF;\n\n FOR r IN\n SELECT (l->>'item_id')::uuid AS item_id, ord\n FROM jsonb_array_elements(p_lines) WITH ORDINALITY AS t(l, ord)\n ORDER BY ord\n LOOP\n v_no := v_no + 1;\n\n SELECT cs.* INTO v_cs\n FROM public.plg_clinical_session_products cs\n WHERE cs.tenant_id = v_tenant AND cs.id = r.item_id\n FOR UPDATE;\n\n -- Linha que não é consumo clínico já nasceu como movimento do razão: ela\n -- não tem o que aprovar, e some da fila por outro caminho.\n IF NOT FOUND THEN\n v_puladas := v_puladas + 1;\n CONTINUE;\n END IF;\n\n IF p_post AND coalesce(v_cs.used_quantity, 0) > 0 THEN\n -- ONDE A BAIXA ACONTECE. Preferência: o local padrão do produto na\n -- unidade, depois o da ficha, depois o primeiro local ativo dela.\n SELECT candidate.location_id INTO v_location\n FROM (\n SELECT s.default_location_id AS location_id,\n CASE WHEN v_cs.unit_id IS NOT NULL AND s.unit_id = v_cs.unit_id THEN 1 ELSE 2 END AS priority\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = v_tenant\n AND s.product_id = v_cs.product_id\n AND s.default_location_id IS NOT NULL\n AND (s.unit_id IS NULL OR s.unit_id = v_cs.unit_id)\n UNION ALL\n SELECT d.default_location_id, 3\n FROM public.plg_inventory_product_details d\n WHERE d.tenant_id = v_tenant\n AND d.product_id = v_cs.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 = v_tenant AND l.is_active\n ) candidate\n JOIN public.plg_inventory_stock_locations l\n ON l.id = candidate.location_id AND l.tenant_id = v_tenant AND l.is_active\n WHERE v_cs.unit_id IS NULL OR l.unit_id = v_cs.unit_id OR l.unit_id IS NULL\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: nenhum local de estoque ativo para a unidade deste consumo'\n USING ERRCODE = '22023';\n END IF;\n\n -- SEM SALDO NÃO SE BAIXA, e quem clicou precisa saber por quê.\n --\n -- A plataforma não deixa o saldo ficar negativo: o gatilho de posição\n -- recusa a saída sem lastro. Em vez de devolver o erro cru do banco, a\n -- linha é separada e volta nomeada — a fila mantém o consumo pendente,\n -- que é o estado certo enquanto a entrada não for dada.\n SELECT coalesce(sum(p.quantity), 0) INTO v_disp\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_cs.product_id\n AND p.stock_location_id = v_location;\n\n IF coalesce(v_disp, 0) < v_cs.used_quantity THEN\n v_sem_saldo := v_sem_saldo + 1;\n v_faltando := v_faltando || jsonb_build_array(jsonb_build_object(\n 'item_id', v_cs.id,\n 'product', (SELECT pr.name FROM public.products pr WHERE pr.id = v_cs.product_id),\n 'needed', v_cs.used_quantity,\n 'available', coalesce(v_disp, 0)));\n CONTINUE;\n END IF;\n\n SELECT p.unit_cost INTO v_cost\n FROM public.plg_inventory_stock_positions p\n WHERE p.tenant_id = v_tenant AND p.product_id = v_cs.product_id\n AND p.stock_location_id = v_location\n ORDER BY p.expiration_date NULLS LAST, p.created_at\n LIMIT 1;\n\n INSERT INTO public.plg_inventory_stock_movements\n (tenant_id, unit_id, product_id, kind, quantity, unit_cost, source_location_id,\n measurement_unit_id, document_type, document_number,\n source_item_type, source_item_id, idempotency_key, line_no, operation_id,\n user_id, metadata)\n VALUES\n (v_tenant, v_cs.unit_id, v_cs.product_id, 'out', -v_cs.used_quantity,\n coalesce(v_cost, 0), v_location, v_cs.used_unit_id, 'consumption',\n coalesce(v_cs.session_id::text, v_cs.id::text),\n 'usage_audit', v_cs.id, v_key, v_no, v_op.op_id, v_actor,\n jsonb_strip_nulls(jsonb_build_object(\n 'source', 'usage_audit_approve',\n 'session_id', v_cs.session_id,\n 'order_item_id', v_cs.order_item_id,\n 'reason', nullif(btrim(p_reason), ''))))\n RETURNING id INTO v_movement;\n\n v_movements := v_movements || app.inventory_movement_json(v_movement);\n v_baixadas := v_baixadas + 1;\n END IF;\n\n -- CONFERIDO é o mesmo carimbo nos dois gestos: o que sai da fila é o que\n -- alguém olhou, tenha ou não baixado.\n UPDATE public.plg_clinical_session_products cs\n SET is_audited = true,\n audited_at = now(),\n audited_by = coalesce(cs.audited_by, v_actor),\n audit_notes = coalesce(nullif(btrim(p_reason), ''), cs.audit_notes),\n updated_at = now()\n WHERE cs.id = v_cs.id;\n v_aprovadas := v_aprovadas + 1;\n END LOOP;\n\n RETURN app.inventory_finish_operation(\n v_tenant, v_op.op_id, CASE WHEN p_post THEN 'confirm' ELSE 'adjust' END, v_key,\n jsonb_build_object(\n 'operation_id', v_op.op_id, 'kind', 'usage_audit_approve',\n 'idempotency_key', v_key, 'status', CASE WHEN p_post THEN 'posted' ELSE 'approved' END,\n 'lines_approved', v_aprovadas, 'lines_posted', v_baixadas,\n 'lines_skipped', v_puladas, 'lines_no_stock', v_sem_saldo,\n 'missing', v_faltando, 'movements', v_movements),\n jsonb_build_object('source', 'usage_audit_approve', 'post', p_post,\n 'lines_approved', v_aprovadas, 'lines_posted', v_baixadas,\n 'lines_no_stock', v_sem_saldo));\nEND $fn$;\n\nGRANT EXECUTE ON FUNCTION public.inventory_approve_usage_batch(jsonb, boolean, text) TO authenticated;\n`\n\nexport const MIGRATION_020_O_PRODUTO_E_VARIAS_COISAS_AO_MESMO_TEMPO = `-- Um produto é VÁRIAS coisas ao mesmo tempo, e cada uma tem a sua ficha.\n--\n-- O V2 guardava o tipo do produto como UM valor dentro de \\`products.metadata\\`\n-- («ingredient» | «sale» | «intermediate» | «asset»). O V1 não: ele tem SETE\n-- interruptores independentes, e cada um liga uma ficha própria no cadastro.\n-- Um shampoo de salão é o caso que quebra o valor único — a casa o usa no\n-- atendimento (insumo) E o revende ao cliente (venda), e com um valor só\n-- alguém tem de escolher qual das duas fichas o produto pode ter.\n--\n-- Então as flags viram COLUNAS, e cada ficha vira uma tabela com a chave no\n-- produto. \\`metadata->>productType\\` continua escrito pelo provider porque é\n-- dele que a faceta da lista («Insumos / Venda / Intermediários / Patrimônio»,\n-- igual à do V1) se serve; ele passa a ser DERIVADO das flags, não a origem.\n--\n-- As fichas são tabelas separadas, e não trinta colunas em\n-- \\`plg_inventory_product_details\\`, porque nenhuma casa usa as quatro: um salão\n-- nunca abre a de patrimônio, e um restaurante nunca abre a de revenda\n-- profissional. Linha que não existe não custa leitura, e a ficha inteira some\n-- junto com o produto (\\`ON DELETE CASCADE\\`).\n\n-- ---------------------------------------------------------------------------\n-- 1. As flags e o resto dos Dados Gerais\n-- ---------------------------------------------------------------------------\n\nALTER TABLE public.plg_inventory_product_details\n ADD COLUMN IF NOT EXISTS is_ingredient boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS is_for_sale boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS is_intermediate boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS is_asset boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS is_produced boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS is_resale boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS track_by_unit_label boolean NOT NULL DEFAULT false,\n -- Rastreabilidade na ENTRADA. No V1 vive na Classificação e vale para\n -- qualquer produto: revenda também tem lote e validade.\n ADD COLUMN IF NOT EXISTS require_batch_for_stock boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS require_expiry_for_stock boolean NOT NULL DEFAULT false,\n ADD COLUMN IF NOT EXISTS commission_percent numeric(7,4) NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS professional_resale_price numeric(16,4),\n ADD COLUMN IF NOT EXISTS chart_account_id uuid,\n ADD COLUMN IF NOT EXISTS content_per_unit numeric(14,4),\n ADD COLUMN IF NOT EXISTS content_unit_id uuid,\n ADD COLUMN IF NOT EXISTS avg_purchase_price numeric(16,4),\n ADD COLUMN IF NOT EXISTS avg_purchase_price_updated_at timestamp with time zone;\n\nCOMMENT ON COLUMN public.plg_inventory_product_details.chart_account_id IS\n 'Conta de despesa em plg_financial_chart_of_accounts. Sem chave estrangeira de propósito: a conta de estoque existe em tenant que não instalou o financeiro.';\nCOMMENT ON COLUMN public.plg_inventory_product_details.content_per_unit IS\n 'Quanto de content_unit_id cabe em UMA measurement_unit_id (1 frasco contém 300 ml).';\nCOMMENT ON COLUMN public.plg_inventory_product_details.avg_purchase_price IS\n 'Custo médio, reescrito a cada entrada de estoque. avg_purchase_price_updated_at carimba a última.';\nCOMMENT ON COLUMN public.plg_inventory_product_details.track_by_unit_label IS\n 'Alto custo / etiquetado: cada unidade é acompanhada individualmente.';\n\nDO $$\nBEGIN\n IF NOT EXISTS (\n SELECT 1 FROM pg_constraint\n WHERE conname = 'plg_inventory_product_details_content_unit_id_fkey'\n ) THEN\n ALTER TABLE public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_content_unit_id_fkey\n FOREIGN KEY (content_unit_id)\n REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\n-- O catálogo que já existe nasceu com UM tipo. Acender a flag correspondente\n-- mantém a tela igual ao que a pessoa cadastrou — sem isto, 169 produtos\n-- abririam o formulário sem nenhuma ficha e pareceriam ter perdido o tipo.\nUPDATE public.plg_inventory_product_details d\n SET is_ingredient = (p.metadata ->> 'productType') = 'ingredient',\n is_for_sale = (p.metadata ->> 'productType') = 'sale',\n is_intermediate = (p.metadata ->> 'productType') = 'intermediate',\n is_asset = (p.metadata ->> 'productType') = 'asset'\n FROM public.products p\n WHERE p.id = d.product_id\n AND p.metadata ->> 'productType' IS NOT NULL\n AND NOT (d.is_ingredient OR d.is_for_sale OR d.is_intermediate OR d.is_asset);\n\n-- Produto que existe sem linha de detalhe nenhuma também precisa da flag, ou\n-- o formulário abre sem ficha e a lista perde a faceta.\nINSERT INTO public.plg_inventory_product_details\n (product_id, tenant_id, is_ingredient, is_for_sale, is_intermediate, is_asset)\nSELECT p.id, p.tenant_id,\n (p.metadata ->> 'productType') = 'ingredient',\n (p.metadata ->> 'productType') = 'sale',\n (p.metadata ->> 'productType') = 'intermediate',\n (p.metadata ->> 'productType') = 'asset'\n FROM public.products p\n WHERE p.metadata ->> 'productType' IS NOT NULL\n AND NOT EXISTS (\n SELECT 1 FROM public.plg_inventory_product_details d WHERE d.product_id = p.id\n )\nON CONFLICT (product_id) DO NOTHING;\n\n-- ---------------------------------------------------------------------------\n-- 2. Códigos de barras — vários por produto, um principal\n-- ---------------------------------------------------------------------------\n--\n-- O produto já tinha UM código em \\`products.metadata->>barcode\\`. Um só não\n-- serve ao balcão: a mesma mercadoria chega em embalagem de 500 ml e de 1 L,\n-- com códigos diferentes, e quem bipa não escolhe qual.\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_barcodes (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n barcode text NOT NULL,\n barcode_type text DEFAULT 'EAN-13' NOT NULL,\n description text,\n is_primary boolean DEFAULT false 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 CONSTRAINT plg_inventory_product_barcodes_pkey PRIMARY KEY (id),\n CONSTRAINT plg_inventory_product_barcodes_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_barcodes_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\nCREATE INDEX IF NOT EXISTS idx_plg_inventory_product_barcodes_product\n ON public.plg_inventory_product_barcodes (product_id);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_plg_inventory_product_barcodes_code\n ON public.plg_inventory_product_barcodes (tenant_id, barcode);\n-- Principal é UM. Sem isto dois «principais» convivem e quem lê a etiqueta\n-- pega o que vier primeiro.\nCREATE UNIQUE INDEX IF NOT EXISTS idx_plg_inventory_product_barcodes_primary\n ON public.plg_inventory_product_barcodes (product_id) WHERE is_primary;\n\n-- ---------------------------------------------------------------------------\n-- 3. Ficha de insumo\n-- ---------------------------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_ingredient_info (\n product_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n minimum_quantity numeric(16,4) DEFAULT 0 NOT NULL,\n maximum_quantity numeric(16,4),\n reorder_point numeric(16,4),\n lead_time_days integer,\n shelf_life_days integer,\n storage_temperature text,\n allowed_supplier_ids 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 CONSTRAINT plg_inventory_product_ingredient_info_pkey PRIMARY KEY (product_id),\n CONSTRAINT plg_inventory_product_ingredient_info_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_ingredient_info_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\nCOMMENT ON COLUMN public.plg_inventory_product_ingredient_info.reorder_point IS\n 'Saldo em que a compra deve ser disparada. Fica ACIMA do mínimo: o mínimo é o que não se pode furar, este é o aviso que chega a tempo.';\n\n-- ---------------------------------------------------------------------------\n-- 4. Ficha de venda e os preços por canal\n-- ---------------------------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_sale_info (\n product_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n menu_description text,\n allergens text,\n preparation_time_minutes integer,\n serves_quantity integer,\n calories integer,\n sold_by_weight boolean DEFAULT false NOT NULL,\n highlight_delivery boolean DEFAULT false NOT NULL,\n available_for_delivery boolean DEFAULT true NOT NULL,\n available_for_counter boolean DEFAULT true NOT NULL,\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 CONSTRAINT plg_inventory_product_sale_info_pkey PRIMARY KEY (product_id),\n CONSTRAINT plg_inventory_product_sale_info_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_sale_info_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\n-- O canal é texto livre, e não um CHECK: a lista do V1 (balcão, delivery\n-- próprio, iFood, 99Food, Keeta) é o cardápio de HOJE, e cada praça tem o seu.\n-- Um CHECK aqui obrigaria uma migration para aceitar o próximo aplicativo.\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_sale_channels (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n product_id uuid NOT NULL,\n channel text NOT NULL,\n price numeric(16,4) DEFAULT 0 NOT NULL,\n 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 CONSTRAINT plg_inventory_product_sale_channels_pkey PRIMARY KEY (id),\n CONSTRAINT plg_inventory_product_sale_channels_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_sale_channels_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_plg_inventory_product_sale_channels_one\n ON public.plg_inventory_product_sale_channels (product_id, channel);\n\n-- ---------------------------------------------------------------------------\n-- 5. Ficha de intermediário\n-- ---------------------------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_intermediate_info (\n product_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n yield_percentage numeric(7,2),\n preparation_time_minutes integer,\n shelf_life_hours integer,\n batch_size numeric(16,4),\n batch_unit_id uuid,\n storage_instructions text,\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 CONSTRAINT plg_inventory_product_intermediate_info_pkey PRIMARY KEY (product_id),\n CONSTRAINT plg_inventory_product_intermediate_info_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_intermediate_info_batch_unit_id_fkey\n FOREIGN KEY (batch_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL,\n CONSTRAINT plg_inventory_product_intermediate_info_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\n-- ---------------------------------------------------------------------------\n-- 6. Ficha de patrimônio\n-- ---------------------------------------------------------------------------\n--\n-- O responsável aponta para \\`people\\` e não para uma tabela de funcionários:\n-- no V2 quem trabalha na casa é uma pessoa como as outras.\n\nCREATE TABLE IF NOT EXISTS public.plg_inventory_product_asset_info (\n product_id uuid NOT NULL,\n tenant_id uuid NOT NULL,\n asset_value numeric(16,4) DEFAULT 0 NOT NULL,\n residual_value numeric(16,4) DEFAULT 0 NOT NULL,\n useful_life_months integer,\n depreciation_rate numeric(7,4),\n serial_number text,\n acquisition_date date,\n warranty_expiry_date date,\n asset_status text DEFAULT 'active' NOT NULL,\n asset_location text,\n responsible_person_id uuid,\n insurance_policy text,\n last_maintenance_date date,\n next_maintenance_date date,\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 CONSTRAINT plg_inventory_product_asset_info_pkey PRIMARY KEY (product_id),\n CONSTRAINT plg_inventory_product_asset_info_product_id_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE CASCADE,\n CONSTRAINT plg_inventory_product_asset_info_responsible_person_id_fkey\n FOREIGN KEY (responsible_person_id) REFERENCES public.people(id) ON DELETE SET NULL,\n CONSTRAINT plg_inventory_product_asset_info_tenant_id_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE\n);\n\n-- ---------------------------------------------------------------------------\n-- 7. A cerca de cada ficha\n-- ---------------------------------------------------------------------------\n--\n-- Mesma regra do resto do plugin: a linha é da casa que a escreveu, e a\n-- pergunta é uma só (\\`user_tenant_ids()\\`), feita uma vez por consulta.\n\nDO $$\nDECLARE\n t text;\nBEGIN\n FOREACH t IN ARRAY ARRAY[\n 'plg_inventory_product_barcodes',\n 'plg_inventory_product_ingredient_info',\n 'plg_inventory_product_sale_info',\n 'plg_inventory_product_sale_channels',\n 'plg_inventory_product_intermediate_info',\n 'plg_inventory_product_asset_info'\n ]\n LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', t);\n EXECUTE format('CREATE INDEX IF NOT EXISTS idx_%s_tenant ON public.%I (tenant_id)', t, t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_select', t);\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',\n t || '_select', t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_insert', t);\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR INSERT TO authenticated WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))',\n t || '_insert', t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_update', t);\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR UPDATE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',\n t || '_update', t);\n\n EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_delete', t);\n EXECUTE format(\n 'CREATE POLICY %I ON public.%I FOR DELETE TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids()))',\n t || '_delete', t);\n\n EXECUTE format('GRANT ALL ON TABLE public.%I TO authenticated', t);\n EXECUTE format('GRANT ALL ON TABLE public.%I TO service_role', t);\n END LOOP;\nEND $$;\n`\n\nexport const MIGRATION_021_O_RAZAO_DIZ_DE_ONDE_VEIO = `-- ---------------------------------------------------------------------------\n-- O razão de estoque diz de onde veio, e a tela consegue abrir a nota.\n-- ---------------------------------------------------------------------------\n-- Comparando uma entrada migrada do V1 com uma que a V2 acabou de gravar:\n--\n-- V1 reason = «Entrada via DANFE NF-e 5411455» document_number = NULL\n-- V2 reason = NULL document_number = «NF-e 4693»\n--\n-- A tela de Movimentações mostra o MOTIVO como legenda debaixo do produto, e é a\n-- resposta para a pergunta nº 1 do FLOW.md do V1 — «de onde vieram essas entradas\n-- que eu não lancei?». Nas linhas novas ela estava escrevendo «Sem motivo\n-- registrado» sobre uma entrada que tinha motivo: a nota fiscal.\n--\n-- Duas causas, as duas aqui:\n--\n-- ① \\`inventory_receive\\` NUNCA GRAVOU \\`reason\\`. A coluna não estava na lista do\n-- INSERT. O chamador até mandava a frase no cabeçalho (\\`notes\\`), mas o\n-- \\`coalesce(v_ln.notes, v_doc->>'notes')\\` dá a vez à anotação DA LINHA, que\n-- toda entrada de nota preenche com a descrição do item. A frase nunca\n-- chegava. Agora existe uma chave própria: \\`reason\\` no cabeçalho, e nada muda\n-- para quem não a manda — continua NULL, como hoje.\n--\n-- ② A VIEW ESCONDIA O CAMINHO DE VOLTA. \\`v_stock_movements\\` não expunha\n-- \\`document_type\\` nem \\`operation_id\\`, que são o que diz «isto é uma NF-e» e\n-- «foi esta operação». Sem eles a tela tem o número da nota escrito e nenhum\n-- jeito de abri-la: \\`plg_fiscalbr_inbox_documents.inventory_operation_id\\`\n-- aponta para a mesma operação, e é por ali que o link se faz.\n--\n-- De quebra, três colunas que o V1 mostra e a V2 não tinha como mostrar: a\n-- UNIDADE junto da quantidade (o V1 escreve «12 SR», «100 UN», e a V2 escrevia só\n-- «12»), e o NOME do fornecedor em vez do uuid.\n--\n-- \\`security_invoker=true\\` fica: sem ele a view lê com os direitos de quem a\n-- criou, e uma view de movimento sem invoker é vazamento entre contas.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE VIEW public.v_stock_movements\nWITH (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 -- NO FIM, e não no meio: \\`CREATE OR REPLACE VIEW\\` só sabe ACRESCENTAR coluna.\n -- Inserir uma antes de \\`product_name\\` faz o Postgres entender que a coluna\n -- está sendo RENOMEADA, e ele recusa — «cannot change name of view column».\n sm.document_type,\n sm.operation_id,\n sm.measurement_unit_id,\n mu.abbreviation AS measurement_unit_abbreviation,\n sup.name AS supplier_name\n FROM plg_inventory_stock_movements sm\n LEFT JOIN products p ON p.id = sm.product_id\n LEFT JOIN plg_inventory_stock_locations sl ON sl.id = sm.source_location_id\n LEFT JOIN plg_inventory_stock_locations dl ON dl.id = sm.destination_location_id\n LEFT JOIN plg_inventory_measurement_units mu ON mu.id = sm.measurement_unit_id\n LEFT JOIN people sup ON sup.id = sm.supplier_id;\n\nCOMMENT ON VIEW public.v_stock_movements IS\n 'O razão de estoque para a tela: movimento + nome do produto, do local, da unidade e do fornecedor, mais document_type/operation_id para a linha conseguir abrir o documento que a originou.';\n\n-- ── \\`inventory_receive\\` passa a gravar o motivo ────────────────────────────\n-- Corpo igual ao que está no cluster, com \\`reason\\` a mais. Reescrever de memória\n-- é como se perde uma regra; isto é o texto real com duas linhas trocadas.\n\nCREATE OR REPLACE FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb DEFAULT '{}'::jsonb, p_idempotency_key text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\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; v_unit uuid; v_line jsonb; v_ln record; v_no integer := 0; v_id uuid;\n v_movements jsonb := '[]'::jsonb; v_positions jsonb := '[]'::jsonb;\n v_doc jsonb := coalesce(p_document, '{}'::jsonb); v_supplier uuid; 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, variant_id, kind, quantity, unit_cost, source_location_id, batch_number, expiration_date, measurement_unit_id,\n supplier_id, document_type, document_number, notes, reason, movement_date, idempotency_key, line_no, operation_id, metadata)\n VALUES\n (v_tenant, v_ln.product_id, v_ln.variant_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'),\n -- O MOTIVO, que é do chamador e não do razão. Ver a migration.\n nullif(v_doc->>'reason', ''), 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 $function$;\n`\n\nexport const MIGRATION_022_RECEBER_ESTOQUE_VOLTA_A_FUNCIONAR = `-- ---------------------------------------------------------------------------\n-- 022 — receber estoque volta a funcionar.\n--\n-- A 021 passou a gravar o \\`reason\\` em \\`inventory_receive\\` — e, na mesma linha,\n-- acrescentou \\`variant_id\\`. Esse campo não existe de dois jeitos:\n--\n-- · \\`plg_inventory_stock_movements\\` NÃO tem a coluna \\`variant_id\\` na cadeia\n-- deste plugin (só \\`reason\\`, desde a baseline). Num banco do zero o INSERT\n-- nomeia coluna inexistente.\n-- · \\`app.inventory_parse_line\\` NÃO devolve \\`variant_id\\` — os OUT dela são\n-- product_id, quantity, unit_cost, batch_number, expiration_date,\n-- measurement_unit_id, declared e notes. Então \\`v_ln.variant_id\\` também\n-- não resolve nos clusters onde alguém criou a coluna por fora.\n--\n-- Nenhum dos dois erros aparece ao CRIAR a função: o corpo de uma plpgsql só é\n-- analisado na primeira chamada. O resultado é que RECEBER ESTOQUE estava\n-- quebrado — em produção, onde a 021 já foi aplicada, e no banco de testes.\n-- Quem pegou foi a suíte pgTAP do inventário, com 14 asserções vermelhas; e\n-- ninguém tinha visto porque a cadeia morria lá na db/162, antes de chegar nos\n-- testes.\n--\n-- Esta migration repõe a função SEM \\`variant_id\\`. O \\`reason\\`, que é o motivo\n-- de existir da 021, fica. Variante de produto é outra feature, e quando\n-- chegar vai precisar de coluna na cadeia e de saída na \\`parse_line\\` — as duas\n-- coisas, não meia.\n--\n-- Não reescreve a 021: ela já está no ledger dos clusters, e arquivo aplicado\n-- não se edita. Idempotente.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.inventory_receive(p_location uuid, p_lines jsonb, p_document jsonb DEFAULT '{}'::jsonb, p_idempotency_key text DEFAULT NULL::text)\n RETURNS jsonb\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\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; v_unit uuid; v_line jsonb; v_ln record; v_no integer := 0; v_id uuid;\n v_movements jsonb := '[]'::jsonb; v_positions jsonb := '[]'::jsonb;\n v_doc jsonb := coalesce(p_document, '{}'::jsonb); v_supplier uuid; 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, reason, 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'),\n -- O MOTIVO, que é do chamador e não do razão. Ver a migration.\n nullif(v_doc->>'reason', ''), 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 $function$;\n`\n\nexport const MIGRATION_023_A_RECEITA_SE_ESCREVE_COM_PERMISSAO = `-- ---------------------------------------------------------------------------\n-- 023 — a receita se escreve com permissão.\n--\n-- The baseline kept the pre-authz insert/update/delete policies on recipes and\n-- product categories next to the *_authz_* ones. Permissive policies are ORed,\n-- so \\`tenant_id IN user_tenant_ids()\\` let any member (viewer, staff, kitchen)\n-- write what inventory.create/edit/delete is supposed to gate.\n--\n-- The old SELECT policies stay on purpose: agenda's service kit\n-- (getServiceKit) reads recipes as reception/professional, who hold no\n-- inventory.read. Narrowing reads is a separate decision.\n-- ---------------------------------------------------------------------------\n\nDROP POLICY IF EXISTS plg_inventory_recipes_insert ON public.plg_inventory_recipes;\nDROP POLICY IF EXISTS plg_inventory_recipes_update ON public.plg_inventory_recipes;\nDROP POLICY IF EXISTS plg_inventory_recipes_delete ON public.plg_inventory_recipes;\n\nDROP POLICY IF EXISTS plg_inventory_product_categories_insert ON public.plg_inventory_product_categories;\nDROP POLICY IF EXISTS plg_inventory_product_categories_update ON public.plg_inventory_product_categories;\nDROP POLICY IF EXISTS plg_inventory_product_categories_delete ON public.plg_inventory_product_categories;\n`\n\nexport const MIGRATION_024_A_CATEGORIA_DO_PRODUTO_E_DO_CATALOGO = `-- ---------------------------------------------------------------------------\n-- 024 — a categoria do produto é do catálogo.\n--\n-- A product category is the \\`categories\\` archetype with kind 'good' (the\n-- catalog contract, and what products.category_id already points to). This\n-- plugin kept a private copy, plg_inventory_product_categories, so the stock\n-- screens read a table nobody else writes: imported and catalog-created\n-- categories never showed up there, and a product could carry two different\n-- categories at once.\n--\n-- The product's category is products.category_id. details.category_id was a\n-- second answer to the same question; it is copied into products where\n-- products had none, and the plugin stops reading or writing it.\n--\n-- Additive and idempotent: rows of the private table are folded into\n-- categories under the same id, then the two FKs move. The private table is\n-- left in place, unreferenced, so this step destroys nothing; dropping it is a\n-- later, reported step.\n-- ---------------------------------------------------------------------------\n\nDO $$\nBEGIN\n IF to_regclass('public.plg_inventory_product_categories') IS NULL THEN\n RETURN;\n END IF;\n\n -- Parents first is not needed: parent_id is written in a second pass.\n INSERT INTO public.categories (id, tenant_id, kind, name, is_active, unit_id, owner_id, created_at, updated_at)\n SELECT c.id, c.tenant_id, 'good', c.name, c.is_active, c.unit_id, c.owner_id, c.created_at, c.updated_at\n FROM public.plg_inventory_product_categories c\n ON CONFLICT (id) DO NOTHING;\n\n UPDATE public.categories k\n SET parent_id = c.parent_id\n FROM public.plg_inventory_product_categories c\n WHERE k.id = c.id AND k.parent_id IS NULL AND c.parent_id IS NOT NULL;\nEND $$;\n\nUPDATE public.products p\n SET category_id = d.category_id\n FROM public.plg_inventory_product_details d\n WHERE d.product_id = p.id AND p.category_id IS NULL AND d.category_id IS NOT NULL\n AND EXISTS (SELECT 1 FROM public.categories c WHERE c.id = d.category_id AND c.tenant_id = p.tenant_id);\n\nALTER TABLE public.plg_inventory_product_details\n DROP CONSTRAINT IF EXISTS plg_inventory_product_details_category_id_fkey;\nALTER TABLE public.plg_inventory_product_details\n ADD CONSTRAINT plg_inventory_product_details_category_id_fkey\n FOREIGN KEY (category_id) REFERENCES public.categories(id) ON DELETE SET NULL;\n\nALTER TABLE public.plg_inventory_count_sessions\n DROP CONSTRAINT IF EXISTS plg_inventory_count_sessions_category_id_fkey;\nALTER TABLE public.plg_inventory_count_sessions\n ADD CONSTRAINT plg_inventory_count_sessions_category_id_fkey\n FOREIGN KEY (category_id) REFERENCES public.categories(id) ON DELETE SET NULL;\n`\n\nexport const MIGRATION_025_A_FICHA_TECNICA_POR_ESTACAO = `-- ---------------------------------------------------------------------------\n-- 025 — the technical sheet, by station.\n--\n-- What the V1 sheet has and the V2 tables did not:\n-- * yield_mode: portion (the sheet IS one unit sold) vs batch (the sheet\n-- produces yield_quantity). Same units, opposite cost math — not inferable.\n-- * the station of each component (recipe_groups.station_id).\n-- * the reading unit of an ingredient line (70 mL of an oil counted in L).\n-- * production outputs with cost split (filé + aparas + pele).\n-- And one write path: inventory_save_recipe() replaces groups, lines and\n-- outputs in ONE transaction. V1 deleted and re-inserted without one, and a\n-- failed insert left the sheet empty (V1-082).\n--\n-- Idempotent.\n-- ---------------------------------------------------------------------------\n\n-- 1. Portion × batch -------------------------------------------------------\nALTER TABLE public.plg_inventory_recipes\n ADD COLUMN IF NOT EXISTS yield_mode text;\n\n-- Same backfill rule as V1 (20261015130000): batch when the product is an\n-- intermediate or is itself an ingredient of another sheet.\nUPDATE public.plg_inventory_recipes r\n SET yield_mode = CASE\n WHEN EXISTS (SELECT 1 FROM public.plg_inventory_product_details d\n WHERE d.product_id = r.product_id AND d.is_intermediate) THEN 'batch'\n WHEN EXISTS (SELECT 1 FROM public.plg_inventory_recipe_ingredients i\n WHERE i.product_id = r.product_id AND i.tenant_id = r.tenant_id) THEN 'batch'\n ELSE 'portion' END\n WHERE r.yield_mode IS NULL;\n\nALTER TABLE public.plg_inventory_recipes ALTER COLUMN yield_mode SET DEFAULT 'portion';\nALTER TABLE public.plg_inventory_recipes ALTER COLUMN yield_mode SET NOT NULL;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipes_yield_mode_check') THEN\n ALTER TABLE public.plg_inventory_recipes ADD CONSTRAINT plg_inventory_recipes_yield_mode_check\n CHECK (yield_mode IN ('portion', 'batch'));\n END IF;\nEND $$;\n\nCOMMENT ON COLUMN public.plg_inventory_recipes.yield_mode IS\n 'portion = the sheet is 1 unit of the product (yield only describes); batch = the sheet produces yield_quantity (cost divides). V1: recipes.yield_mode.';\n\n-- 2. Station of a component -----------------------------------------------\nALTER TABLE public.plg_inventory_recipe_groups\n ADD COLUMN IF NOT EXISTS station_id uuid;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_groups_station_fkey') THEN\n ALTER TABLE public.plg_inventory_recipe_groups ADD CONSTRAINT plg_inventory_recipe_groups_station_fkey\n FOREIGN KEY (station_id) REFERENCES public.plg_inventory_production_stations(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\nCOMMENT ON COLUMN public.plg_inventory_recipe_groups.station_id IS\n 'Estação de Produção do componente. V1: recipe_groups.production_station_id.';\n\n-- 3. Reading unit of an ingredient line -----------------------------------\n-- quantity stays in the ingredient''s BASE unit (unit_id); this is only how\n-- the line is read and typed.\nALTER TABLE public.plg_inventory_recipe_ingredients\n ADD COLUMN IF NOT EXISTS display_unit_id uuid;\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_ingredients_display_unit_fkey') THEN\n ALTER TABLE public.plg_inventory_recipe_ingredients ADD CONSTRAINT plg_inventory_recipe_ingredients_display_unit_fkey\n FOREIGN KEY (display_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\nEND $$;\n\n-- 4. Production outputs ---------------------------------------------------\nCREATE TABLE IF NOT EXISTS public.plg_inventory_recipe_outputs (\n id uuid DEFAULT gen_random_uuid() NOT NULL,\n tenant_id uuid NOT NULL,\n unit_id uuid,\n recipe_id uuid NOT NULL,\n product_id uuid NOT NULL,\n output_type text DEFAULT 'main' NOT NULL,\n expected_quantity numeric(14,4) NOT NULL,\n measurement_unit_id uuid,\n cost_share numeric(9,4),\n display_order integer DEFAULT 0 NOT NULL,\n created_at timestamp with time zone DEFAULT now() NOT NULL,\n updated_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\nCOMMENT ON TABLE public.plg_inventory_recipe_outputs IS\n 'Saídas da produção de uma ficha (filé + aparas + pele). cost_share em branco em todas = rateio pelo valor de mercado; descarte não leva custo. V1: recipe_outputs.';\n\nDO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_pkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_pkey PRIMARY KEY (id);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_tenant_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_tenant_fkey\n FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_unit_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_unit_fkey\n FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_recipe_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_recipe_fkey\n FOREIGN KEY (recipe_id) REFERENCES public.plg_inventory_recipes(id) ON DELETE CASCADE;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_product_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_product_fkey\n FOREIGN KEY (product_id) REFERENCES public.products(id);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_uom_fkey') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_uom_fkey\n FOREIGN KEY (measurement_unit_id) REFERENCES public.plg_inventory_measurement_units(id) ON DELETE SET NULL;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_type_check') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_type_check\n CHECK (output_type IN ('main', 'coproduct', 'byproduct', 'waste'));\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_qty_check') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_qty_check\n CHECK (expected_quantity > 0);\n END IF;\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_inventory_recipe_outputs_share_check') THEN\n ALTER TABLE ONLY public.plg_inventory_recipe_outputs ADD CONSTRAINT plg_inventory_recipe_outputs_share_check\n CHECK (cost_share IS NULL OR (cost_share >= 0 AND cost_share <= 100));\n END IF;\nEND $$;\n\nCREATE INDEX IF NOT EXISTS plg_inventory_recipe_outputs_recipe_idx\n ON public.plg_inventory_recipe_outputs USING btree (tenant_id, recipe_id, display_order);\n\nALTER TABLE public.plg_inventory_recipe_outputs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_inventory_recipe_outputs FORCE ROW LEVEL SECURITY;\n\nGRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.plg_inventory_recipe_outputs TO authenticated;\nGRANT ALL ON TABLE public.plg_inventory_recipe_outputs TO service_role;\n\nDROP TRIGGER IF EXISTS plg_inventory_recipe_outputs_updated_at ON public.plg_inventory_recipe_outputs;\nCREATE TRIGGER plg_inventory_recipe_outputs_updated_at BEFORE UPDATE ON public.plg_inventory_recipe_outputs\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nDROP POLICY IF EXISTS plg_inventory_recipe_outputs_authz_select ON public.plg_inventory_recipe_outputs;\nCREATE POLICY plg_inventory_recipe_outputs_authz_select ON public.plg_inventory_recipe_outputs\n FOR SELECT TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (unit_id IS NULL OR (SELECT app.has_unit(plg_inventory_recipe_outputs.unit_id)))\n AND (SELECT app.has_permission('inventory.read', plg_inventory_recipe_outputs.unit_id)));\n\nDROP POLICY IF EXISTS plg_inventory_recipe_outputs_authz_write ON public.plg_inventory_recipe_outputs;\nCREATE POLICY plg_inventory_recipe_outputs_authz_write ON public.plg_inventory_recipe_outputs\n FOR ALL TO authenticated USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('inventory.edit', plg_inventory_recipe_outputs.unit_id)))\n WITH CHECK (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('inventory.edit', plg_inventory_recipe_outputs.unit_id)));\n\n-- 5. Having a sheet = being produced ----------------------------------------\n-- V1 flips is_produced when the sheet is saved; sheets that crossed over\n-- before the flag existed never got it, so the list and the product tab\n-- did not see them.\nUPDATE public.plg_inventory_product_details d\n SET is_produced = true\n WHERE NOT d.is_produced\n AND EXISTS (SELECT 1 FROM public.plg_inventory_recipes r\n WHERE r.product_id = d.product_id AND r.is_active);\n\n-- 6. The one write path -----------------------------------------------------\n-- SECURITY INVOKER on purpose: every row goes through the same RLS the screen\n-- has (inventory.create / inventory.edit on the recipe''s unit).\nCREATE OR REPLACE FUNCTION public.inventory_save_recipe(p_recipe jsonb)\nRETURNS uuid\nLANGUAGE plpgsql\nSECURITY INVOKER\nSET search_path = ''\nAS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_id uuid := nullif(p_recipe->>'id', '')::uuid;\n v_product uuid := nullif(p_recipe->>'productId', '')::uuid;\n v_unit uuid;\n v_group jsonb;\n v_group_id uuid;\n v_line jsonb;\n v_out jsonb;\n v_gi int := 0;\n v_li int;\n v_oi int := 0;\n v_cost numeric := nullif(p_recipe->>'unitCost', '')::numeric;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'no active tenant' USING ERRCODE = '42501';\n END IF;\n IF v_product IS NULL THEN\n RAISE EXCEPTION 'productId is required' USING ERRCODE = '22023';\n END IF;\n IF coalesce(trim(p_recipe->>'name'), '') = '' THEN\n RAISE EXCEPTION 'name is required' USING ERRCODE = '22023';\n END IF;\n\n IF v_id IS NULL THEN\n -- One active sheet per product: reuse the one already there.\n SELECT r.id INTO v_id FROM public.plg_inventory_recipes r\n WHERE r.tenant_id = v_tenant AND r.product_id = v_product AND r.is_active\n ORDER BY r.updated_at DESC LIMIT 1;\n END IF;\n\n IF v_id IS NULL THEN\n INSERT INTO public.plg_inventory_recipes\n (tenant_id, product_id, name, description, yield_quantity, yield_unit_id, yield_mode,\n preparation_time_minutes, instructions, is_active, unit_id, owner_id)\n VALUES\n (v_tenant, v_product, trim(p_recipe->>'name'), nullif(p_recipe->>'description', ''),\n coalesce(nullif(p_recipe->>'yieldQuantity', '')::numeric, 1),\n nullif(p_recipe->>'yieldUnitId', '')::uuid,\n coalesce(nullif(p_recipe->>'yieldMode', ''), 'portion'),\n nullif(p_recipe->>'preparationTimeMinutes', '')::int,\n nullif(p_recipe->>'instructions', ''), true,\n nullif(p_recipe->>'unitId', '')::uuid, auth.uid())\n RETURNING id, unit_id INTO v_id, v_unit;\n ELSE\n UPDATE public.plg_inventory_recipes SET\n name = trim(p_recipe->>'name'),\n description = nullif(p_recipe->>'description', ''),\n product_id = v_product,\n yield_quantity = coalesce(nullif(p_recipe->>'yieldQuantity', '')::numeric, 1),\n yield_unit_id = nullif(p_recipe->>'yieldUnitId', '')::uuid,\n yield_mode = coalesce(nullif(p_recipe->>'yieldMode', ''), 'portion'),\n preparation_time_minutes = nullif(p_recipe->>'preparationTimeMinutes', '')::int,\n instructions = nullif(p_recipe->>'instructions', ''),\n is_active = true,\n updated_at = now()\n WHERE id = v_id AND tenant_id = v_tenant\n RETURNING unit_id INTO v_unit;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'recipe not found or not writable' USING ERRCODE = '42501';\n END IF;\n END IF;\n\n DELETE FROM public.plg_inventory_recipe_ingredients WHERE recipe_id = v_id AND tenant_id = v_tenant;\n DELETE FROM public.plg_inventory_recipe_groups WHERE recipe_id = v_id AND tenant_id = v_tenant;\n DELETE FROM public.plg_inventory_recipe_outputs WHERE recipe_id = v_id AND tenant_id = v_tenant;\n\n FOR v_group IN SELECT * FROM jsonb_array_elements(coalesce(p_recipe->'groups', '[]'::jsonb)) LOOP\n INSERT INTO public.plg_inventory_recipe_groups\n (tenant_id, unit_id, recipe_id, name, station_id, preparation_notes, estimated_minutes, display_order)\n VALUES\n (v_tenant, v_unit, v_id,\n coalesce(nullif(trim(v_group->>'name'), ''), 'Componente ' || (v_gi + 1)),\n nullif(v_group->>'stationId', '')::uuid,\n nullif(v_group->>'preparationNotes', ''),\n nullif(v_group->>'estimatedMinutes', '')::int,\n v_gi)\n RETURNING id INTO v_group_id;\n\n v_li := 0;\n FOR v_line IN SELECT * FROM jsonb_array_elements(coalesce(v_group->'ingredients', '[]'::jsonb)) LOOP\n -- unit_id on a line is the MEASUREMENT unit (base of the ingredient),\n -- not the house: the house of a line is its recipe's.\n INSERT INTO public.plg_inventory_recipe_ingredients\n (tenant_id, recipe_id, group_id, product_id, quantity, unit_id, display_unit_id, notes, display_order)\n VALUES\n (v_tenant, v_id, v_group_id, (v_line->>'productId')::uuid,\n (v_line->>'quantity')::numeric,\n nullif(v_line->>'unitId', '')::uuid,\n nullif(v_line->>'displayUnitId', '')::uuid,\n nullif(v_line->>'notes', ''), v_li);\n v_li := v_li + 1;\n END LOOP;\n v_gi := v_gi + 1;\n END LOOP;\n\n FOR v_out IN SELECT * FROM jsonb_array_elements(coalesce(p_recipe->'outputs', '[]'::jsonb)) LOOP\n INSERT INTO public.plg_inventory_recipe_outputs\n (tenant_id, unit_id, recipe_id, product_id, output_type, expected_quantity,\n measurement_unit_id, cost_share, display_order)\n VALUES\n (v_tenant, v_unit, v_id, (v_out->>'productId')::uuid,\n coalesce(nullif(v_out->>'outputType', ''), 'main'),\n (v_out->>'expectedQuantity')::numeric,\n nullif(v_out->>'measurementUnitId', '')::uuid,\n CASE WHEN v_out->>'outputType' = 'waste' THEN NULL\n ELSE nullif(v_out->>'costShare', '')::numeric END,\n v_oi);\n v_oi := v_oi + 1;\n END LOOP;\n\n -- Having a sheet = being produced; and the sheet's cost per unit becomes the\n -- product's cost — it is what another sheet reads when this one is its input.\n INSERT INTO public.plg_inventory_product_details (product_id, tenant_id, is_produced)\n VALUES (v_product, v_tenant, true)\n ON CONFLICT (product_id) DO UPDATE SET is_produced = true;\n\n IF v_cost IS NOT NULL AND v_cost > 0 THEN\n UPDATE public.products SET cost = round(v_cost, 4), updated_at = now()\n WHERE id = v_product AND tenant_id = v_tenant;\n END IF;\n\n RETURN v_id;\nEND;\n$$;\n\nREVOKE ALL ON FUNCTION public.inventory_save_recipe(jsonb) FROM PUBLIC, anon;\nGRANT EXECUTE ON FUNCTION public.inventory_save_recipe(jsonb) TO authenticated;\n`\n\nexport const MIGRATION_026_STOCK_COST_KNOWS_ITS_CURRENCY = `-- ============================================================================\n-- 026 — stock cost knows its currency\n--\n-- \\`unit_cost\\` was a bare number. With a shop in Rio and one in Barcelona, and\n-- shirts paid for in dollars, three currencies would have met in one weighted\n-- average.\n--\n-- The rule: the cost a position carries is ALWAYS in the currency of the unit\n-- that holds the stock, so every sum and average that already exists stays\n-- right. What was actually paid, when it was paid in something else, is kept\n-- beside it (\\`source_currency\\`, \\`source_unit_cost\\`, \\`fx_rate\\`) and converted\n-- once, on the way in.\n--\n-- A receipt says the currency on the document (or the line):\n-- inventory_receive(loc, lines, '{\"currency\":\"USD\",\"fx_rate\":5.42}')\n-- With no rate given, the tenant's rate for the day is used; with none on\n-- file, the receipt is refused rather than booked at a made-up cost.\n--\n-- Moving stock between units of different currencies is refused for now: the\n-- same cost number would land in the other currency unconverted.\n-- ============================================================================\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_movements' AND column_name = 'currency') THEN\n ALTER TABLE public.plg_inventory_stock_movements ADD COLUMN currency text NOT NULL DEFAULT 'BRL';\n ALTER TABLE public.plg_inventory_stock_movements ALTER COLUMN currency DROP DEFAULT;\n END IF;\n IF NOT EXISTS (SELECT 1 FROM information_schema.columns\n WHERE table_schema = 'public' AND table_name = 'plg_inventory_stock_positions' AND column_name = 'currency') THEN\n ALTER TABLE public.plg_inventory_stock_positions ADD COLUMN currency text NOT NULL DEFAULT 'BRL';\n ALTER TABLE public.plg_inventory_stock_positions ALTER COLUMN currency DROP DEFAULT;\n END IF;\nEND $$;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS source_currency text;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS source_unit_cost numeric;\nALTER TABLE public.plg_inventory_stock_movements ADD COLUMN IF NOT EXISTS fx_rate numeric;\n\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.currency IS 'Currency of unit_cost/total_cost: the unit that holds the stock.';\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.source_currency IS 'Currency the goods were paid in, when not the unit''s.';\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.source_unit_cost IS 'Unit cost as paid, in source_currency.';\nCOMMENT ON COLUMN public.plg_inventory_stock_movements.fx_rate IS '1 source_currency = fx_rate of the unit''s currency, as used for this entry.';\nCOMMENT ON COLUMN public.plg_inventory_stock_positions.currency IS 'Currency of unit_cost: the unit that holds this balance.';\n\nCREATE OR REPLACE FUNCTION app.inventory_movements_currency()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nDECLARE\n v_unit_cur text := app.unit_currency(NEW.tenant_id, NEW.unit_id);\n v_dst_unit uuid;\n v_src text := nullif(upper(btrim(coalesce(NEW.source_currency, ''))), '');\nBEGIN\n NEW.currency := v_unit_cur;\n\n IF NEW.destination_location_id IS NOT NULL THEN\n SELECT l.unit_id INTO v_dst_unit FROM public.plg_inventory_stock_locations l WHERE l.id = NEW.destination_location_id;\n IF app.unit_currency(NEW.tenant_id, v_dst_unit) <> v_unit_cur THEN\n RAISE EXCEPTION 'Transferência entre filiais de moedas diferentes (% → %) ainda não é suportada: dê saída em uma e entrada na outra, informando o custo.',\n v_unit_cur, app.unit_currency(NEW.tenant_id, v_dst_unit)\n USING ERRCODE = '0A000';\n END IF;\n END IF;\n\n IF v_src IS NULL OR v_src = v_unit_cur THEN\n NEW.source_currency := NULL; NEW.source_unit_cost := NULL; NEW.fx_rate := NULL;\n RETURN NEW;\n END IF;\n\n NEW.source_currency := v_src;\n NEW.source_unit_cost := coalesce(NEW.source_unit_cost, NEW.unit_cost, 0);\n -- The tenant's rate table belongs to financial, which may not be installed.\n IF NEW.fx_rate IS NULL AND to_regprocedure('public.plg_financial_fx_rate(uuid,text,text,date)') IS NOT NULL THEN\n EXECUTE 'SELECT public.plg_financial_fx_rate($1, $2, $3, $4)'\n INTO NEW.fx_rate USING NEW.tenant_id, v_src, v_unit_cur, NEW.movement_date;\n END IF;\n IF NEW.fx_rate IS NULL OR NEW.fx_rate <= 0 THEN\n RAISE EXCEPTION 'Informe a taxa de câmbio de % para % desta entrada (ou cadastre a taxa do dia).', v_src, v_unit_cur\n USING ERRCODE = '22023';\n END IF;\n NEW.unit_cost := round(NEW.source_unit_cost * NEW.fx_rate, 4);\n NEW.total_cost := abs(NEW.quantity) * NEW.unit_cost;\n RETURN NEW;\nEND $function$;\n\n-- Named to fire after \\`plg_inventory_stock_movements_before_insert\\`, which\n-- stamps the unit and the cost this converts.\nDROP TRIGGER IF EXISTS plg_inventory_stock_movements_currency ON public.plg_inventory_stock_movements;\nCREATE TRIGGER plg_inventory_stock_movements_currency\n BEFORE INSERT ON public.plg_inventory_stock_movements\n FOR EACH ROW EXECUTE FUNCTION app.inventory_movements_currency();\n\nCREATE OR REPLACE FUNCTION app.inventory_positions_currency()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\n SET search_path TO ''\nAS $function$\nDECLARE v_unit uuid;\nBEGIN\n SELECT l.unit_id INTO v_unit FROM public.plg_inventory_stock_locations l WHERE l.id = NEW.stock_location_id;\n NEW.currency := app.unit_currency(NEW.tenant_id, coalesce(v_unit, NEW.unit_id));\n RETURN NEW;\nEND $function$;\nDROP TRIGGER IF EXISTS plg_inventory_stock_positions_currency ON public.plg_inventory_stock_positions;\nCREATE TRIGGER plg_inventory_stock_positions_currency\n BEFORE INSERT ON public.plg_inventory_stock_positions\n FOR EACH ROW EXECUTE FUNCTION app.inventory_positions_currency();\n\n-- The receipt passes the document's currency through. Patched in place: the\n-- live body differs from the file that created it.\nDO $patch$\nDECLARE\n v_fn regprocedure := 'public.inventory_receive(uuid, jsonb, jsonb, text)'::regprocedure;\n v_def text := pg_get_functiondef(v_fn);\n v_cols constant text := 'idempotency_key, line_no, operation_id, metadata)';\n v_vals constant text := 'v_key, v_no, v_op.op_id, v_ln.declared)';\nBEGIN\n IF position('source_currency' in v_def) > 0 THEN\n RETURN; -- already passes it (a replay, or a later rewrite)\n END IF;\n IF position(v_cols in v_def) = 0 OR position(v_vals in v_def) = 0 THEN\n RAISE EXCEPTION '026: inventory_receive no longer has the INSERT this extends; patch it by hand';\n END IF;\n v_def := overlay(v_def PLACING 'idempotency_key, line_no, operation_id, metadata, source_currency, fx_rate)'\n FROM position(v_cols in v_def) FOR length(v_cols));\n v_def := overlay(v_def PLACING\n 'v_key, v_no, v_op.op_id, v_ln.declared,' || E'\\\\n'\n || ' nullif(upper(btrim(coalesce(v_line->>''currency'', v_doc->>''currency'', ''''))), ''''),' || E'\\\\n'\n || ' coalesce(nullif(v_line->>''fx_rate'', '''')::numeric, nullif(v_doc->>''fx_rate'', '''')::numeric))'\n FROM position(v_vals in v_def) FOR length(v_vals));\n EXECUTE v_def;\nEND $patch$;\n`\n\nexport const MIGRATION_027_A_RECEIPT_NAMES_THE_LINE_IT_CAME_FROM = `-- ============================================================================\n-- 027 — a receipt names the line it came from\n--\n-- Stock received because of a bill had no tie to the bill line: the ledger\n-- kept \\`source_item_type\\` / \\`source_item_id\\` columns, but \\`inventory_receive\\`\n-- never filled them, so \"did this line enter stock?\" was answered by guessing\n-- from the invoice number. A line of the receipt can now say where it came\n-- from, and the receipt writes it down.\n--\n-- Patched in place, as 026 did: the live body differs from the files.\n-- ============================================================================\n\nDO $patch$\nDECLARE\n v_fn regprocedure := 'public.inventory_receive(uuid, jsonb, jsonb, text)'::regprocedure;\n v_def text := pg_get_functiondef(v_fn);\n v_cols constant text := 'metadata, source_currency, fx_rate)';\n v_vals constant text := 'nullif(v_doc->>''fx_rate'', '''')::numeric))';\nBEGIN\n IF position('source_item_id' in v_def) > 0 THEN\n RETURN; -- already writes it (a replay, or a later rewrite)\n END IF;\n IF position(v_cols in v_def) = 0 OR position(v_vals in v_def) = 0 THEN\n RAISE EXCEPTION '027: inventory_receive no longer has the INSERT this extends; patch it by hand';\n END IF;\n v_def := overlay(v_def PLACING 'metadata, source_currency, fx_rate, source_item_type, source_item_id)'\n FROM position(v_cols in v_def) FOR length(v_cols));\n v_def := overlay(v_def PLACING\n 'nullif(v_doc->>''fx_rate'', '''')::numeric),' || E'\\\\n'\n || ' nullif(v_line->>''source_item_type'', ''''), nullif(v_line->>''source_item_id'', '''')::uuid)'\n FROM position(v_vals in v_def) FOR length(v_vals));\n EXECUTE v_def;\nEND $patch$;\n\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_source_item_idx\n ON public.plg_inventory_stock_movements (tenant_id, source_item_id) WHERE source_item_id IS NOT NULL;\n`\n\nexport const MIGRATION_028_A_RECEIPT_KEEPS_THE_VARIANT = `-- ============================================================================\n-- 028 — a receipt keeps the variant\n--\n-- \\`inventory_receive\\` read \\`variant_id\\` off each line, checked it belonged to\n-- the product, and then did not write it: every receipt landed on the\n-- product's default variant. A shirt received as 10 M and 9 G was 19 of\n-- \"Padrão\". The line's variant now reaches the ledger row, which is what the\n-- per-variant balance is computed from.\n--\n-- Patched in place, as 026 and 027 did.\n--\n-- The column itself was never in this plugin's chain (022 says so): pools got\n-- it by hand, a database built from zero did not. It is declared here, in the\n-- shape the pools have. The value is read off the line's JSON, which exists in\n-- every version of the function; \\`v_ln.variant_id\\` only exists where the\n-- parser was widened by hand.\n-- ============================================================================\n\nALTER TABLE public.plg_inventory_stock_movements\n ADD COLUMN IF NOT EXISTS variant_id uuid REFERENCES public.product_variants(id) ON DELETE SET NULL;\nCREATE INDEX IF NOT EXISTS plg_inventory_stock_movements_variant_idx\n ON public.plg_inventory_stock_movements (tenant_id, variant_id) WHERE variant_id IS NOT NULL;\n\nDO $patch$\nDECLARE\n v_fn regprocedure := 'public.inventory_receive(uuid, jsonb, jsonb, text)'::regprocedure;\n v_def text := pg_get_functiondef(v_fn);\n v_cols constant text := 'source_item_type, source_item_id)';\n v_vals constant text := 'nullif(v_line->>''source_item_id'', '''')::uuid)';\nBEGIN\n IF position('source_item_type, source_item_id, variant_id)' in v_def) > 0 THEN\n RETURN; -- already writes it (a replay, or a later rewrite)\n END IF;\n IF position(v_cols in v_def) = 0 OR position(v_vals in v_def) = 0 THEN\n RAISE EXCEPTION '028: inventory_receive no longer has the INSERT this extends; patch it by hand';\n END IF;\n v_def := overlay(v_def PLACING 'source_item_type, source_item_id, variant_id)'\n FROM position(v_cols in v_def) FOR length(v_cols));\n v_def := overlay(v_def PLACING 'nullif(v_line->>''source_item_id'', '''')::uuid, nullif(v_line->>''variant_id'', '''')::uuid)'\n FROM position(v_vals in v_def) FOR length(v_vals));\n EXECUTE v_def;\nEND $patch$;\n`\n\nexport const MIGRATION_029_A_REVERSAL_UNDOES_THE_SAME_VARIANT = `-- ============================================================================\n-- 029 — a reversal undoes the same variant\n--\n-- 028 made a receipt keep the variant it was for. \\`inventory_reverse\\` copies\n-- the row it undoes and left the variant out, so undoing \"6 of M\" tried to\n-- take 6 from the product's default variant — which has none, and the\n-- reversal was refused (\"would take variant … below zero\"). A receipt by size\n-- could be made and never corrected.\n--\n-- The reversal now carries the variant of the row it reverses.\n-- Patched in place, like 026–028.\n-- ============================================================================\n\nDO $patch$\nDECLARE\n v_fn regprocedure := 'public.inventory_reverse(text, text)'::regprocedure;\n v_def text := pg_get_functiondef(v_fn);\n v_new text;\n -- The function has two INSERTs (one per branch); both copy the row they undo.\n v_cols constant text := 'reverses_movement_id, idempotency_key, line_no, operation_id, metadata)';\n v_vals1 constant text := 'jsonb_build_object(''reversed_movement_id'', r.id))';\n v_vals2 constant text := '''reversed_kind'', r.kind))';\nBEGIN\n IF position('r.variant_id' in v_def) > 0 THEN\n RETURN; -- already carries it (a replay, or a later rewrite)\n END IF;\n v_new := replace(v_def, v_cols, 'reverses_movement_id, idempotency_key, line_no, operation_id, metadata, variant_id)');\n v_new := replace(v_new, v_vals1, 'jsonb_build_object(''reversed_movement_id'', r.id), r.variant_id)');\n v_new := replace(v_new, v_vals2, '''reversed_kind'', r.kind), r.variant_id)');\n -- Every INSERT that gained the column must have gained the value.\n IF (length(v_new) - length(replace(v_new, 'metadata, variant_id)', ''))) / length('metadata, variant_id)')\n <> (length(v_new) - length(replace(v_new, ', r.variant_id)', ''))) / length(', r.variant_id)')\n OR position('metadata, variant_id)' in v_new) = 0 THEN\n RAISE EXCEPTION '029: inventory_reverse no longer has the INSERTs this extends; patch it by hand';\n END IF;\n EXECUTE v_new;\nEND $patch$;\n`\n\nexport const MIGRATION_030_THE_MINIMUM_CAN_BE_SAVED = `-- ============================================================================\n-- 030 — the minimum can be saved\n--\n-- The product form saves its minimum with an upsert on\n-- (tenant_id, product_id, unit_id). The only unique index on those columns\n-- was the expression index (tenant_id, product_id, COALESCE(unit_id, zero)),\n-- which ON CONFLICT cannot infer from a column list, so every save came back\n-- 42P10 and the client never looked at the error: \"Quantidade Mínima\" was\n-- dropped in silence.\n--\n-- A plain column index with NULLS NOT DISTINCT is an arbiter for that\n-- conflict target and treats the tenant-wide row (unit_id NULL) as one row,\n-- which is what the expression index already enforced. Both are kept: they\n-- agree on every row, and dropping the old one is not this fix's business.\n--\n-- Hand-applied on cluster-squash-test on 2026-10-22 under this same name, so\n-- this file must be a no-op there.\n--\n-- Second part: the Insumo tab had its own minimum/maximum, stored on\n-- plg_inventory_product_ingredient_info, which no alert or restock list\n-- reads. The tab no longer offers them. Whatever was typed there is copied\n-- into the tenant-wide settings row when the product has none yet, so the\n-- number the person entered becomes the one that is acted on. The columns\n-- stay; nothing is dropped.\n-- ============================================================================\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_inventory_product_settings_upsert_key\n ON public.plg_inventory_product_settings (tenant_id, product_id, unit_id) NULLS NOT DISTINCT;\n\nINSERT INTO public.plg_inventory_product_settings (tenant_id, product_id, unit_id, min_quantity, max_quantity)\nSELECT i.tenant_id,\n i.product_id,\n NULL,\n GREATEST(COALESCE(i.minimum_quantity, 0), 0),\n CASE WHEN i.maximum_quantity >= 0 THEN i.maximum_quantity END\n FROM public.plg_inventory_product_ingredient_info i\n JOIN public.products p ON p.id = i.product_id AND p.tenant_id = i.tenant_id\n WHERE (COALESCE(i.minimum_quantity, 0) > 0 OR i.maximum_quantity IS NOT NULL)\n AND NOT EXISTS (\n SELECT 1\n FROM public.plg_inventory_product_settings s\n WHERE s.tenant_id = i.tenant_id\n AND s.product_id = i.product_id\n AND s.unit_id IS NULL)\nON CONFLICT (tenant_id, product_id, unit_id) DO NOTHING;\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 { id: \"003_stock_count_closes_through_ledger\", sql: MIGRATION_003_STOCK_COUNT_CLOSES_THROUGH_LEDGER },\n { id: \"004_a_posicao_de_estoque_atravessa\", sql: MIGRATION_004_A_POSICAO_DE_ESTOQUE_ATRAVESSA },\n { id: \"005_a_posicao_e_consequencia_do_movimento\", sql: MIGRATION_005_A_POSICAO_E_CONSEQUENCIA_DO_MOVIMENTO },\n { id: \"006_a_producao_tem_ordem_e_estacao\", sql: MIGRATION_006_A_PRODUCAO_TEM_ORDEM_E_ESTACAO },\n { id: \"007_a_producao_atravessa\", sql: MIGRATION_007_A_PRODUCAO_ATRAVESSA },\n { id: \"008_o_grupo_da_receita_tambem_e_de_uma_casa\", sql: MIGRATION_008_O_GRUPO_DA_RECEITA_TAMBEM_E_DE_UMA_CASA },\n { id: \"009_a_direcao_do_movimento_nao_esta_no_numero\", sql: MIGRATION_009_A_DIRECAO_DO_MOVIMENTO_NAO_ESTA_NO_NUMERO },\n { id: \"010_a_entrada_de_notas_atravessa\", sql: MIGRATION_010_A_ENTRADA_DE_NOTAS_ATRAVESSA },\n { id: \"011_o_consumo_tem_duas_origens\", sql: MIGRATION_011_O_CONSUMO_TEM_DUAS_ORIGENS },\n { id: \"012_o_consumo_clinico_nao_precisa_da_tabela_de_itens_inteira\", sql: MIGRATION_012_O_CONSUMO_CLINICO_NAO_PRECISA_DA_TABELA_DE_ITENS_INTEIRA },\n { id: \"013_a_fila_de_auditoria_tem_uma_janela\", sql: MIGRATION_013_A_FILA_DE_AUDITORIA_TEM_UMA_JANELA },\n { id: \"014_a_sessao_se_busca_uma_a_uma\", sql: MIGRATION_014_A_SESSAO_SE_BUSCA_UMA_A_UMA },\n { id: \"015_lateral_sem_cerca_nao_e_lateral\", sql: MIGRATION_015_LATERAL_SEM_CERCA_NAO_E_LATERAL },\n { id: \"016_a_data_do_consumo_e_uma_coluna\", sql: MIGRATION_016_A_DATA_DO_CONSUMO_E_UMA_COLUNA },\n { id: \"017_aprovar_e_baixar_sao_dois_gestos\", sql: MIGRATION_017_APROVAR_E_BAIXAR_SAO_DOIS_GESTOS },\n { id: \"018_o_nome_nao_sai_da_vista\", sql: MIGRATION_018_O_NOME_NAO_SAI_DA_VISTA },\n { id: \"019_sem_saldo_nao_se_baixa\", sql: MIGRATION_019_SEM_SALDO_NAO_SE_BAIXA },\n { id: \"020_o_produto_e_varias_coisas_ao_mesmo_tempo\", sql: MIGRATION_020_O_PRODUTO_E_VARIAS_COISAS_AO_MESMO_TEMPO },\n { id: \"021_o_razao_diz_de_onde_veio\", sql: MIGRATION_021_O_RAZAO_DIZ_DE_ONDE_VEIO },\n { id: \"022_receber_estoque_volta_a_funcionar\", sql: MIGRATION_022_RECEBER_ESTOQUE_VOLTA_A_FUNCIONAR },\n { id: \"023_a_receita_se_escreve_com_permissao\", sql: MIGRATION_023_A_RECEITA_SE_ESCREVE_COM_PERMISSAO },\n { id: \"024_a_categoria_do_produto_e_do_catalogo\", sql: MIGRATION_024_A_CATEGORIA_DO_PRODUTO_E_DO_CATALOGO },\n { id: \"025_a_ficha_tecnica_por_estacao\", sql: MIGRATION_025_A_FICHA_TECNICA_POR_ESTACAO },\n { id: \"026_stock_cost_knows_its_currency\", sql: MIGRATION_026_STOCK_COST_KNOWS_ITS_CURRENCY },\n { id: \"027_a_receipt_names_the_line_it_came_from\", sql: MIGRATION_027_A_RECEIPT_NAMES_THE_LINE_IT_CAME_FROM },\n { id: \"028_a_receipt_keeps_the_variant\", sql: MIGRATION_028_A_RECEIPT_KEEPS_THE_VARIANT },\n { id: \"029_a_reversal_undoes_the_same_variant\", sql: MIGRATION_029_A_REVERSAL_UNDOES_THE_SAME_VARIANT },\n { id: \"030_the_minimum_can_be_saved\", sql: MIGRATION_030_THE_MINIMUM_CAN_BE_SAVED },\n]\n","import React from 'react'\nimport type { DetailTab, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { InventoryPage } from './views/InventoryPage'\nimport { UnitStockLocationsWidget } from './views/UnitStockLocationsWidget'\nimport { UNIT_DETAIL_ZONES } from '@fayz-ai/admin'\nimport { createInventoryDashboardWidgets } from './views/dashboardWidgets'\nimport type { ResolvedInventoryConfig } from './context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { StockMovement } from '@fayz-ai/inventory/domain/movement'\nimport { registerTranslations } from '@fayz-ai/core'\nimport { PluginSettingsPanel } from '@fayz-ai/admin'\nimport { createInventoryDataProvider, createInventoryStore } from '@fayz-ai/inventory/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\n/** Uma tela que outro plugin empresta ao Estoque. */\nexport interface InventoryExtraView {\n /** Vira o segmento da URL: `/inventory/<id>`. Em inglês, como toda rota do V2. */\n id: string\n label: string\n icon?: string\n render: () => React.ReactNode\n /**\n * Telas irmãs sob a mesma aba, como o V1 agrupa cinco sob «Notas Fiscais».\n * Sem isto, quatro telas de nota virariam quatro abas no Estoque e afogariam\n * Produtos e Movimentações.\n */\n children?: Array<{ id: string; label: string; render: () => React.ReactNode }>\n /**\n * O nome da PRÓPRIA tela quando ela entra como primeiro filho do grupo. Sem\n * isto o Estoque chamava toda tela emprestada de «Entrada», que era o nome de\n * uma delas — e o grupo de notas quis o nome do V1, «Manifesto de Notas».\n */\n defaultChildLabel?: string\n}\n\nexport interface InventoryNavShortcut {\n /** The inner view id; the entry routes to `/inventory/<view>`. */\n view: string\n label: string\n icon?: string\n /** Defaults to inventory read. A borrowed view (fiscal notes) passes its own. */\n permission?: { feature: string; action: 'read' }\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 /**\n * Telas que OUTRO plugin contribui para dentro do Estoque, como abas irmãs de\n * Produtos, Movimentações e Contagens.\n *\n * Existe porque «Entrada de Notas» é assunto de estoque e não assunto do rail:\n * no V1 o caminho é `Estoque → Notas Fiscais → Entrada de Notas`, e montá-la\n * como linha solta no menu quebra o mapa mental de quem vem do V1 — a pessoa\n * procura dentro do Estoque e não acha. Quem dá entrada de nota é o\n * `plugin-fiscal-br`, que não pode reivindicar uma aba do Estoque sem esta\n * porta.\n *\n * A ordem na faixa é a ordem deste array, depois das abas próprias.\n */\n extraViews?: InventoryExtraView[]\n /**\n * Inner views the app also wants as direct rail entries under Estoque\n * (e.g. `products-list`, `inbound-notes`). Opt-in: without it the module is\n * one rail row and every screen lives in its own tab strip.\n */\n navShortcuts?: InventoryNavShortcut[]\n /**\n * Tabs another plugin contributes to the product record — the shop's photos,\n * say. The catalog product is this plugin's; what else is known about it is\n * not, so the app composes it here instead of this plugin importing theirs.\n * Shown after the plugin's own tabs.\n */\n productDetailTabs?: DetailTab[]\n /**\n * O documento que originou um movimento de estoque — a nota de entrada, hoje —\n * desenhado dentro do modal que o Estoque abre. Ver `ResolvedInventoryConfig`.\n */\n documentModal?: (movement: StockMovement, close: () => void) => React.ReactNode\n scope?: PluginScope\n /**\n * Como o Estoque desenha a PRÓPRIA navegação (Produtos, Movimentações,\n * Contagens, Receitas).\n *\n * O padrão vem do shell, e num app cujo default é `sidebar` esse padrão diz\n * \"o rail lista as minhas sub-telas\" — promessa que ninguém cumpre por este\n * módulo: no rail ele é UMA linha, e o que tem dentro é tela irmã, não\n * assunto novo. O resultado era o Estoque abrindo sem faixa de abas nenhuma.\n *\n * Mesma porta que `crm`, `marketing` e `financial` já usam.\n */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\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', labelKey: 'inventory.productType.ingredient' },\n { value: 'sale', label: 'For Sale', labelKey: 'inventory.productType.sale' },\n { value: 'intermediate', label: 'Intermediate', labelKey: 'inventory.productType.intermediate' },\n { value: 'asset', label: 'Asset', labelKey: 'inventory.productType.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 moduleNav: options?.moduleNav,\n extraViews: options?.extraViews ?? [],\n productDetailTabs: options?.productDetailTabs ?? [],\n documentModal: options?.documentModal,\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 ?? 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 // Como esta conta refaz o módulo com as opções DELA. Ver PluginRebuild:\n // a fábrica roda no carregamento do aplicativo, muito antes de a\n // configuração da conta existir, e sem isto `app.tenant_plugins.config`\n // não tinha como chegar aqui. A fusão é RASA e por bloco — a conta troca\n // `modules` inteiro ou não o troca —, que é o mesmo contrato que a chamada\n // do aplicativo já tem.\n rebuild: (tenantConfig) =>\n createInventoryPlugin({ ...options, ...(tenantConfig as InventoryPluginOptions) }),\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 // The shell nests these under `/inventory` by route prefix, and only when\n // the parent sorts first — a lower position would leave them top-level.\n ...(options?.navShortcuts ?? []).map((shortcut, i) => ({\n section: options?.navSection ?? 'main',\n position: (options?.navPosition ?? 4) + (i + 1) / 100,\n label: shortcut.label,\n route: `/inventory/${shortcut.view}`,\n icon: shortcut.icon,\n permission: shortcut.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 {\n id: 'inventory-unit-stock-locations',\n zone: UNIT_DETAIL_ZONES.stockLocations,\n component: UnitStockLocationsWidget as unknown as React.ComponentType<unknown>,\n order: 0,\n },\n ],\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: 'Quais produtos estão com estoque baixo?' },\n { label: 'Quais insumos precisam de reposição?', verticalId: 'food' as const },\n { label: 'Mostre um resumo do estoque' },\n { label: 'Quais são os produtos mais usados?' },\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, { config }),\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 { createInventoryDataProvider }\nexport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nexport type { ResolvedInventoryConfig } from './context'\n\nexport {\n MOVEMENT_TYPES,\n MOVEMENT_TYPE_VALUES,\n LEGACY_PT_MOVEMENT_TYPE,\n movementTypeSpec,\n normalizeMovementType,\n} from '@fayz-ai/inventory/domain/movement'\nexport type { MovementType, MovementTypeSpec } from '@fayz-ai/inventory/domain/movement'\nexport type {\n ConsumeRecipeForSourceInput,\n ReverseRecipeConsumptionInput,\n InventoryConsumptionResult,\n InventoryConsumptionStatus,\n InventoryConsumptionSkipReason,\n} from '@fayz-ai/inventory/domain/consumption'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/views/dashboardWidgets.tsx","../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/index.ts"],"names":["T","React"],"mappings":"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","file":"index.js","sourcesContent":["import React, { useEffect } from 'react'\nimport { ArrowUpRight, ArrowDownRight, AlertTriangle, PackageX } 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, Badge, Skeleton,\n defineKpiWidget, defineCustomWidget,\n} from '@fayz-ai/ui'\nimport { InventoryContextProvider, useInventoryConfig, useInventoryStore, formatCurrency, type ResolvedInventoryConfig } from '../context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { InventoryUIState } from '@fayz-ai/inventory/store'\nimport { noProductHasMinimum } from '@fayz-ai/inventory/domain/stock'\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\n/**\n * O número que explica os outros.\n *\n * Com o depósito vazio e nenhum mínimo cadastrado, \"Estoque Baixo\" marca ZERO —\n * e o cartão mais importante do painel vira o mais enganoso. Este conta quantos\n * produtos ainda não têm de que estar abaixo. O V1 resolve o mesmo caso ao\n * contrário: trata mínimo 0 como alerta, 93% do catálogo entra na reposição\n * urgente e ninguém olha mais a lista.\n */\nfunction NoMinimumKpi() {\n const summary = useInventoryStore((s) => s.summary)\n useEnsureSummary()\n const n = summary?.noMinimumCount ?? 0\n return (\n <KpiCard\n label=\"Sem mínimo definido\"\n icon=\"AlertTriangle\"\n value={String(n)}\n sub={n > 0 ? 'Não entram no alerta de estoque baixo' : 'Todo produto tem mínimo'}\n />\n )\n}\n\nfunction RestockRowSkeleton() {\n return (\n <ul className=\"space-y-2\">\n {[0, 1, 2].map((i) => (\n <li key={i} className=\"flex items-center gap-3\">\n <Skeleton className=\"h-4 w-40\" />\n <span className=\"flex-1\" />\n <Skeleton className=\"h-4 w-16\" />\n </li>\n ))}\n </ul>\n )\n}\n\n/** Quantidade com a unidade de medida junto — o número sozinho não informa. */\nfunction qty(value: number, unit?: string): string {\n const n = value.toLocaleString('pt-BR', { maximumFractionDigits: 3 })\n return unit ? `${n} ${unit}` : n\n}\n\n/**\n * O que precisa de compra, com o MOTIVO em cada linha.\n *\n * \"Abaixo do mínimo\" vem antes de \"sem estoque\": o abaixo do mínimo é uma\n * compra que a casa já decidiu que precisa fazer; o zerado pode ser um cadastro\n * que nunca entrou em uso — e aqui são 162 de 169, o que seria uma lista de\n * alarme falso do tamanho do catálogo.\n */\nfunction RestockPanel() {\n const rows = useInventoryStore((s) => s.restock)\n const summary = useInventoryStore((s) => s.summary)\n const fetchRestock = useInventoryStore((s) => s.fetchRestock)\n useEnsureSummary()\n useEffect(() => { void fetchRestock() }, [])\n\n const belowMinimum = (rows ?? []).filter((r) => r.reason === 'below-minimum')\n const outOfStock = (rows ?? []).filter((r) => r.reason === 'out-of-stock')\n const nobodyHasMinimum = noProductHasMinimum(summary)\n\n return (\n <Card>\n <CardHeader><CardTitle>Precisa de reposição</CardTitle></CardHeader>\n <CardContent>\n {rows === null ? (\n <RestockRowSkeleton />\n ) : nobodyHasMinimum ? (\n // Sem nenhum mínimo cadastrado esta lista não é um alerta: é o\n // catálogo inteiro. Dizer o que falta vale mais do que listá-lo.\n <div className=\"text-sm\">\n <p className=\"font-medium\">Nenhum produto tem estoque mínimo definido.</p>\n <p className=\"mt-1 text-muted-foreground\">\n Sem o mínimo na ficha do produto não há reposição a calcular — o alerta\n de estoque baixo fica em zero mesmo com o depósito vazio.\n {/* O número vem do RESUMO, não do tamanho da lista: a lista é\n cortada em 50 e escrever o corte como se fosse o total é\n mentir com precisão — aqui daria \"50\" onde são 162. */}\n {(summary?.outOfStockCount ?? 0) > 0 && ` Hoje ${summary!.outOfStockCount === 1 ? 'há 1 produto' : `há ${summary!.outOfStockCount} produtos`} com saldo zerado.`}\n </p>\n </div>\n ) : rows.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n Nada a repor: todo produto está acima do mínimo.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {[...belowMinimum, ...outOfStock].slice(0, 8).map((row) => (\n <li key={row.productId} className=\"flex items-center gap-3 text-sm\">\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate\">{row.name}</span>\n {row.categoryName && (\n <span className=\"block truncate text-xs text-muted-foreground\">{row.categoryName}</span>\n )}\n </span>\n {row.reason === 'below-minimum' ? (\n <Badge variant=\"secondary\" className=\"gap-1 shrink-0\">\n <AlertTriangle className=\"h-3 w-3\" aria-hidden=\"true\" />\n {qty(row.currentQuantity, row.unit)} de {qty(row.minQuantity, row.unit)}\n </Badge>\n ) : (\n <Badge variant=\"outline\" className=\"gap-1 shrink-0\">\n <PackageX className=\"h-3 w-3\" aria-hidden=\"true\" />\n Sem estoque\n </Badge>\n )}\n </li>\n ))}\n </ul>\n )}\n </CardContent>\n </Card>\n )\n}\n\n/**\n * A divisão do catálogo — barras ordenadas, UM matiz, com ênfase.\n *\n * Não é rosca: oito classes que todas significam alguma coisa passam do que uma\n * pizza consegue separar, e a fatia dominante aqui é \"Sem categoria\", que não é\n * uma categoria — é um cadastro por fazer. Em rosca ela vira só a maior fatia;\n * em barras com ênfase ela diz o que custa. A cor não carrega identidade\n * (série única, sem legenda): o rótulo carrega, e o texto usa tinta de texto.\n */\nfunction CategoryMixPanel() {\n const mix = useInventoryStore((s) => s.categoryMix)\n const fetchMix = useInventoryStore((s) => s.fetchCategoryMix)\n useEffect(() => { void fetchMix() }, [])\n\n const total = (mix ?? []).reduce((sum, c) => sum + c.count, 0)\n const uncategorized = (mix ?? []).find((c) => c.categoryId === null)\n\n return (\n <Card>\n <CardHeader><CardTitle>Produtos por categoria</CardTitle></CardHeader>\n <CardContent>\n {mix === null ? (\n <RestockRowSkeleton />\n ) : total === 0 ? (\n <p className=\"text-sm text-muted-foreground\">Nenhum produto ativo para distribuir.</p>\n ) : (\n <>\n <ul className=\"space-y-2\">\n {mix.slice(0, 8).map((row) => {\n const pct = Math.round((row.count / total) * 100)\n const isGap = row.categoryId === null\n return (\n <li key={row.categoryId ?? 'none'} className=\"flex items-center gap-3 text-sm\">\n <span className=\"w-40 shrink-0 truncate\" title={row.name}>{row.name}</span>\n <span\n className=\"relative h-2 flex-1 overflow-hidden rounded-full bg-muted\"\n aria-hidden=\"true\"\n >\n <span\n className={isGap ? 'absolute inset-y-0 left-0 rounded-full bg-muted-foreground/60' : 'absolute inset-y-0 left-0 rounded-full bg-primary'}\n style={{ width: `${pct}%` }}\n />\n </span>\n {/* Rótulo direto em todas as linhas: são oito, e ler um\n eixo para oito valores é trabalho que a tela pode poupar. */}\n <span className=\"w-20 shrink-0 text-right tabular-nums text-muted-foreground\">\n {row.count} · {pct}%\n </span>\n </li>\n )\n })}\n </ul>\n {uncategorized && uncategorized.count > 0 && (\n <p className=\"mt-3 text-xs text-muted-foreground\">\n {uncategorized.count} de {total} produtos ainda não têm categoria — é o\n que impede este painel, os filtros e as isenções de taxa de dizerem\n algo útil.\n </p>\n )}\n </>\n )}\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 // Escondido na home global (é diagnóstico de cadastro, não manchete do\n // negócio) e visível no painel do estoque, que é onde se conserta.\n defineKpiWidget({ id: 'inventory.kpi.no-minimum', title: 'Sem mínimo definido', domain: 'inventory', defaultOrder: 4, defaultVisible: false, component: withCtx(NoMinimumKpi) }),\n defineCustomWidget({ id: 'inventory.panel.recent-activity', title: 'inventory.dashboard.recentActivity', domain: 'inventory', span: 2, defaultOrder: 10, surfaces: ['plugin-home'], component: withCtx(RecentActivityPanel) }),\n defineCustomWidget({ id: 'inventory.panel.restock', title: 'Precisa de reposição', domain: 'inventory', span: 2, defaultOrder: 11, surfaces: ['plugin-home'], component: withCtx(RestockPanel) }),\n defineCustomWidget({ id: 'inventory.panel.category-mix', title: 'Produtos por categoria', domain: 'inventory', span: 2, defaultOrder: 12, surfaces: ['plugin-home'], component: withCtx(CategoryMixPanel) }),\n ]\n}\n","import type { PluginRegistryDef } from '@fayz-ai/core'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { RECORD_GROUP, recordRailFields, activeFacet } from '@fayz-ai/core'\nimport { PRODUCT_CATEGORY_KIND, T } from '@fayz-ai/inventory/data/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 // Declares the supplier as someone the house pays, which is what keeps\n // the \"Bank accounts\" section on the record.\n { key: 'payeeAccount', label: 'Bank account', type: 'bank', showInTable: false, showInDetail: false },\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 formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'abbreviation', label: 'Abbreviation', type: 'text', required: true, showInTable: true, group: 'identity' },\n ...recordRailFields({ tagsTable: T.measurementUnits, activeLabel: 'Ativo', unit: false }),\n ],\n data: { table: T.measurementUnits, tenantScoped: true },\n}\n\nconst productCategoryEntity: EntityDef = {\n name: 'Product Category',\n namePlural: 'Product Categories',\n // O botao de criar interpola o SUBSTANTIVO, e `name` e um literal ingles:\n // sem estas chaves o CrudListView omite o nome e escreve so «Adicionar»,\n // enquanto a lista ao lado escreve «Novo Produto». Ver EntityDef.nameKey.\n nameKey: 'inventory.entity.productCategory',\n namePluralKey: 'inventory.entity.productCategory.plural',\n icon: 'Tag',\n displayField: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'parentId', label: 'Parent', type: 'text', showInTable: false, group: 'identity' },\n ...recordRailFields({ tagsTable: T.productCategories, activeLabel: 'Ativo', unit: false }),\n ],\n data: {\n table: T.productCategories,\n schema: 'public',\n tenantScoped: true,\n filters: { kind: PRODUCT_CATEGORY_KIND },\n defaults: { kind: PRODUCT_CATEGORY_KIND },\n },\n}\n\n// Em português porque a tela é: as vizinhas desta lista («Ativo», «Unidade»,\n// «Identificação») já estavam traduzidas, e duas colunas em inglês no meio\n// delas leem como campo de outro sistema.\nconst stockLocationEntity: EntityDef = {\n name: 'Local de Estoque',\n namePlural: 'Locais de Estoque',\n nameKey: 'inventory.entity.stockLocation',\n namePluralKey: 'inventory.entity.stockLocation.plural',\n icon: 'Warehouse',\n displayField: 'name',\n formColumns: 2,\n facets: [activeFacet({ active: 'Ativos', inactive: 'Inativos', all: 'Todos' })],\n fieldGroups: [{ id: 'identity', label: 'Identificação', columns: 2 }, { ...RECORD_GROUP }],\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, group: 'identity' },\n { key: 'description', label: 'Descrição', type: 'textarea', showInTable: true, group: 'identity' },\n ...recordRailFields({ tagsTable: T.stockLocations, activeLabel: 'Ativo', unit: 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: 'Onde a mercadoria fica guardada',\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 // O tour navega até o cadastro de produto; os passos sem âncora ficam de\n // briefing (a tela é um CRUD genérico, sem campos ancoráveis por enquanto).\n steps: [\n { do: 'O Estoque mora aqui.', anchor: 'nav./inventory', route: '/inventory' },\n { do: 'Produtos ficam neste menu.', anchor: 'modnav.products', route: '/inventory/products/list' },\n { do: 'Cadastre um produto novo aqui.', anchor: 'action.new-product', route: '/inventory/products/list' },\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 // Navega até a tela de entrada; a `practice` deixa a pessoa dar a entrada.\n steps: [\n { do: 'O Estoque mora aqui.', anchor: 'nav./inventory', route: '/inventory' },\n { do: 'Abra Entrada neste menu para lançar a compra que chegou.', anchor: 'modnav.stock-entry', route: '/inventory/stock/entry' },\n { do: 'Saída é para o que foi descartado, perdido ou usado fora de um atendimento.' },\n { do: 'O histórico mostra tudo, inclusive o que o sistema lançou sozinho.' },\n ],\n practice: [\n { anchor: 'inventory.entry-product', label: 'Escolha o produto que chegou' },\n { anchor: 'inventory.entry-save', label: 'Confirme a entrada', final: true },\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: 'Fichas Técnicas',\n about:\n 'A receita de cada produto que a casa produz: os insumos e as quantidades, por componente e estação, com o custo calculado e o CMV contra o preço de venda.',\n route: '/inventory/recipes/list',\n requires: [\n {\n title: 'Insumos cadastrados',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'o campo Insumo da ficha encontra o item ao digitar (produto com Insumo ou Intermediário ligado)',\n },\n {\n title: 'Custo de cada insumo',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'a coluna Custo da linha mostra R$ em vez de —; o lápis da própria ficha resolve',\n },\n {\n title: 'Preço de venda no produto da ficha',\n feature: 'inventory.produtos',\n route: '/inventory/products/list',\n check: 'o CMV da ficha mostra % em vez de —',\n },\n ],\n steps: [\n { do: 'Estoque › Fichas Técnicas › Nova Ficha Técnica, e escolha o produto.', route: '/inventory/recipes/list' },\n { do: 'Confira Rendimento, Unidade e Tipo de rendimento: Porção quando a ficha é 1 unidade vendida, Lote quando ela produz o rendimento.' },\n { do: 'Adicionar Grupo para cada componente (ex.: Preparo da Costela, Montagem) e escolha a estação.' },\n { do: 'Em cada componente, Adicionar Item: insumo, quantidade e unidade. Custo — = clique no lápis e informe o preço.' },\n { do: 'Salvar Ficha Técnica. O custo por unidade vira o custo do produto.' },\n ],\n rules: [\n 'Ter ficha é ser produzido: salvar liga «Produto Produzido» no produto.',\n 'O custo da ficha substitui o custo do produto, e é ele que outra ficha lê quando este produto entra como insumo.',\n 'Saídas da produção: ou todas as aproveitáveis têm %, somando 100, ou todas ficam em branco (rateio pelo valor de mercado).',\n 'A sugestão da IA preenche a tela e não grava nada; ela substitui os componentes que estavam lá.',\n ],\n answers: [\n 'Por que o produto não tem a aba Ficha Técnica?',\n 'Qual a diferença entre rendimento Porção e Lote?',\n 'Por que o insumo aparece com custo —?',\n 'Salvei a ficha e o custo do produto mudou sozinho. É normal?',\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 '@fayz-ai/inventory/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.nav.panel\": \"Panel\",\n \"inventory.panel.columnProduct\": \"Product\",\n \"inventory.panel.columnLocation\": \"Location\",\n \"inventory.panel.columnBatch\": \"Batch\",\n \"inventory.panel.columnExpiry\": \"Expiry\",\n \"inventory.panel.columnQuantity\": \"Qty / min\",\n \"inventory.panel.columnValue\": \"Value\",\n \"inventory.panel.empty\": \"No stock position for this selection.\",\n \"inventory.panel.totalLines\": \"Lines\",\n \"inventory.panel.totalValue\": \"Stock value\",\n \"inventory.panel.unsupported\": \"This app does not expose the stock panel.\",\n \"inventory.filters.stockState\": \"Stock status\",\n \"inventory.filters.health.negative\": \"Negative\",\n \"inventory.filters.health.below_min\": \"Below min\",\n \"inventory.filters.health.zero\": \"Zero\",\n \"inventory.filters.health.ok\": \"OK\",\n \"inventory.filters.expiry\": \"Expiry\",\n \"inventory.filters.expiry.all\": \"All\",\n \"inventory.filters.expiry.expired\": \"Expired\",\n \"inventory.filters.expiry.le30\": \"Expires in 30 days\",\n \"inventory.filters.expiry.le60\": \"Expires in 60 days\",\n \"inventory.filters.expiry.le90\": \"Expires in 90 days\",\n \"inventory.filters.expiry.none\": \"No expiry\",\n \"inventory.filters.batchPlaceholder\": \"Batch\",\n \"inventory.filters.productPlaceholder\": \"Search product...\",\n \"inventory.filters.countState\": \"Count state\",\n \"inventory.filters.countAll\": \"All\",\n \"inventory.filters.countPending\": \"To count\",\n \"inventory.filters.countDone\": \"Counted\",\n \"inventory.filters.itemSearchPlaceholder\": \"Search product or code...\",\n \"inventory.filters.title\": \"Filters\",\n \"inventory.filters.apply\": \"Search\",\n \"inventory.filters.pending\": \"Filters changed\",\n \"inventory.filters.pendingHint\": \"The list still shows the previous selection. Click Search to apply.\",\n \"inventory.filters.clear\": \"Clear\",\n \"inventory.filters.more\": \"More filters\",\n \"inventory.filters.less\": \"Fewer filters\",\n \"inventory.filters.from\": \"From\",\n \"inventory.filters.to\": \"To\",\n \"inventory.filters.allTypes\": \"All types\",\n \"inventory.filters.location\": \"Location\",\n \"inventory.filters.allLocations\": \"All locations\",\n \"inventory.filters.category\": \"Category\",\n \"inventory.filters.allCategories\": \"All categories\",\n \"inventory.filters.kind\": \"Item type\",\n \"inventory.filters.allKinds\": \"All\",\n \"inventory.filters.status\": \"Status\",\n \"inventory.filters.allStatuses\": \"All\",\n \"inventory.stock.pendingRetry\": \"Confirmation is pending. Do not create another entry. Retry the same details before leaving this screen.\",\n \"inventory.stock.refreshAfterCommit\": \"Movement recorded. Refresh the screen to see the balance.\",\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 \"inventory.entity.stockLocation\": \"Stock Location\",\n \"inventory.entity.stockLocation.plural\": \"Stock Locations\",\n \"inventory.entity.productCategory\": \"Category\",\n \"inventory.entity.productCategory.plural\": \"Categories\",\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\": \"Summary\",\n \"inventory.nav.entry\": \"Entry\",\n \"inventory.nav.exit\": \"Exit\",\n \"inventory.nav.history\": \"History\",\n \"inventory.nav.inventory\": \"Inventory\",\n \"inventory.nav.list\": \"List\",\n \"inventory.nav.new\": \"New\",\n \"inventory.nav.products\": \"Products\",\n \"inventory.nav.stock\": \"Movements\",\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 produced products yet\",\n \"inventory.recipes.exporting\": \"Building the recipes spreadsheet…\",\n \"inventory.recipes.exported\": \"Spreadsheet downloaded\",\n \"inventory.sheet.print\": \"Print\",\n \"inventory.sheet.printSaveFirst\": \"Save the sheet before printing\",\n \"inventory.recipes.noCategory\": \"No category\",\n \"inventory.recipes.filterKind\": \"Type\",\n \"inventory.recipes.filterKindAll\": \"All types\",\n \"inventory.recipes.kindSale\": \"Sale\",\n \"inventory.recipes.kindIntermediate\": \"Intermediate\",\n \"inventory.recipes.filterCategory\": \"Category\",\n \"inventory.recipes.filterCategoryAll\": \"All categories\",\n \"inventory.recipes.filterCmv\": \"CMV\",\n \"inventory.recipes.filterCmvAll\": \"Any CMV\",\n \"inventory.recipes.cmvHigh\": \"CMV above {{pct}}%\",\n \"inventory.recipes.cmvGood\": \"Good CMV (below {{pct}}%)\",\n \"inventory.recipes.cmvAttention\": \"CMV watch ({{from}}–{{to}}%)\",\n \"inventory.recipes.cmvNone\": \"No CMV\",\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.minimum\": \"Minimum\",\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.modules\": \"Modules\",\n \"inventory.settings.modulesDesc\": \"What this house shows inside Inventory\",\n \"inventory.settings.recipes\": \"Recipes\",\n \"inventory.settings.recipesDesc\": \"The bill of materials that says what each product consumes\",\n \"inventory.settings.requisitions\": \"Requisitions\",\n \"inventory.settings.requisitionsDesc\": \"Internal requests for material between areas\",\n \"inventory.settings.usageAuditDesc\": \"What left stock against what was sold\",\n \"inventory.settings.temperature\": \"Temperature\",\n \"inventory.settings.temperatureDesc\": \"Temperature log for refrigerated 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 // Product fichas — ported from the V1 product form (the per-type tabs).\n \"inventory.productForm.commissionPercent\": \"Commission % (sale)\",\n \"inventory.productForm.commissionPercentHint\": \"What the professional earns when selling this product.\",\n \"inventory.productForm.chartAccount\": \"Chart of accounts\",\n \"inventory.productForm.avgPurchasePrice\": \"Average purchase price\",\n \"inventory.productForm.avgPurchasePriceHint\": \"Rewritten on every stock entry.\",\n \"inventory.productForm.packaging\": \"Packaging and conversions\",\n \"inventory.productForm.packagingDesc\": \"How the house buys, when that differs from how it counts.\",\n \"inventory.productForm.contentPerUnit\": \"Content per unit\",\n \"inventory.productForm.contentPerUnitHint\": \"How much fits in ONE stock unit (a bottle holds 300 ml).\",\n \"inventory.productForm.contentUnit\": \"Content unit\",\n \"inventory.productForm.purchaseUnit\": \"Purchase unit\",\n \"inventory.productForm.conversionFactor\": \"Quantity per package\",\n \"inventory.productForm.conversionFactorHint\": \"How many stock units come in one purchase unit.\",\n \"inventory.productForm.flagIngredient\": \"Ingredient\",\n \"inventory.productForm.flagIngredientHint\": \"Shows up in recipes.\",\n \"inventory.productForm.flagForSale\": \"For sale\",\n \"inventory.productForm.flagForSaleHint\": \"Menu, POS, catalogue.\",\n \"inventory.productForm.flagIntermediate\": \"Intermediate\",\n \"inventory.productForm.flagIntermediateHint\": \"Made to be used later (sauce, dough).\",\n \"inventory.productForm.flagAsset\": \"Asset\",\n \"inventory.productForm.flagAssetHint\": \"Equipment: it goes on the balance sheet, it is not consumed.\",\n \"inventory.productForm.flagProduced\": \"Produced product\",\n \"inventory.productForm.flagProducedHint\": \"Comes from a recipe — enables the recipe sheet.\",\n \"inventory.productForm.flagResale\": \"Resale\",\n \"inventory.productForm.flagResaleHint\": \"Goods meant to be resold to the customer.\",\n \"inventory.productForm.flagTracked\": \"High value / labelled\",\n \"inventory.productForm.flagTrackedHint\": \"Each unit is tracked individually.\",\n \"inventory.productForm.professionalResalePrice\": \"Professional resale price\",\n \"inventory.productForm.professionalResalePriceHint\": \"Charged when the professional resells to the end customer.\",\n \"inventory.productForm.requireBatch\": \"Require batch on entry\",\n \"inventory.productForm.requireBatchHint\": \"Blocks stock entry without a batch number.\",\n \"inventory.productForm.requireExpiry\": \"Require expiry on entry\",\n \"inventory.productForm.requireExpiryHint\": \"Blocks stock entry without an expiry date.\",\n \"inventory.productForm.notes\": \"Notes\",\n \"inventory.productForm.ingredientSection\": \"Ingredient\",\n \"inventory.productForm.ingredientSectionDesc\": \"What purchasing needs to restock in time.\",\n \"inventory.productForm.ingReorderPoint\": \"Reorder point\",\n \"inventory.productForm.ingReorderPointHint\": \"Sits ABOVE the minimum: the warning that still arrives in time to buy.\",\n \"inventory.productForm.ingLeadTime\": \"Lead time (days)\",\n \"inventory.productForm.ingShelfLife\": \"Shelf life (days)\",\n \"inventory.productForm.ingStorageTemp\": \"Storage temperature\",\n \"inventory.productForm.saleSection\": \"Sale\",\n \"inventory.productForm.saleSectionDesc\": \"What the menu and the counter show the customer.\",\n \"inventory.productForm.salePrepTime\": \"Prep time (min)\",\n \"inventory.productForm.saleServes\": \"Serves (people)\",\n \"inventory.productForm.saleCalories\": \"Calories (kcal)\",\n \"inventory.productForm.saleMenuDescription\": \"Menu description\",\n \"inventory.productForm.saleAllergens\": \"Allergens\",\n \"inventory.productForm.saleAllergensPlaceholder\": \"Contains gluten, lactose\",\n \"inventory.productForm.saleSoldByWeight\": \"Sold by weight\",\n \"inventory.productForm.saleHighlightDelivery\": \"Highlight on delivery\",\n \"inventory.productForm.saleAvailableDelivery\": \"Available for delivery\",\n \"inventory.productForm.saleAvailableCounter\": \"Available at the counter\",\n \"inventory.productForm.saleChannelsSection\": \"Channel prices\",\n \"inventory.productForm.saleChannelsSectionDesc\": \"Leave a channel empty to use the base sale price.\",\n \"inventory.productForm.intermediateSection\": \"Intermediate\",\n \"inventory.productForm.intermediateSectionDesc\": \"What production needs to prepare the batch.\",\n \"inventory.productForm.intYield\": \"Yield (%)\",\n \"inventory.productForm.intPrepTime\": \"Prep time (min)\",\n \"inventory.productForm.intShelfLifeHours\": \"Shelf life after prep (h)\",\n \"inventory.productForm.intBatchSize\": \"Batch size\",\n \"inventory.productForm.intBatchUnit\": \"Batch unit\",\n \"inventory.productForm.intStorage\": \"Storage instructions\",\n \"inventory.productForm.assetSection\": \"Asset\",\n \"inventory.productForm.assetSectionDesc\": \"The equipment the house owns, and who answers for it.\",\n \"inventory.productForm.assetValue\": \"Asset value\",\n \"inventory.productForm.assetResidualValue\": \"Residual value\",\n \"inventory.productForm.assetUsefulLife\": \"Useful life (months)\",\n \"inventory.productForm.assetDepreciation\": \"Annual depreciation (%)\",\n \"inventory.productForm.assetSerial\": \"Serial number\",\n \"inventory.productForm.assetAcquisition\": \"Acquisition date\",\n \"inventory.productForm.assetWarranty\": \"Warranty until\",\n \"inventory.productForm.assetStatus\": \"Status\",\n \"inventory.productForm.assetLocation\": \"Location\",\n \"inventory.productForm.assetLocationPlaceholder\": \"Room 2, shelf B\",\n \"inventory.productForm.assetResponsible\": \"Responsible\",\n \"inventory.productForm.assetInsurance\": \"Insurance policy\",\n \"inventory.productForm.assetLastMaintenance\": \"Last maintenance\",\n \"inventory.productForm.assetNextMaintenance\": \"Next maintenance\",\n \"inventory.productForm.taxSection\": \"Tax\",\n \"inventory.productForm.taxSectionDesc\": \"What the invoice must say about this product. Empty means the tax group decides.\",\n \"inventory.productForm.taxGroup\": \"Tax group\",\n \"inventory.productForm.taxGroupHint\": \"Set up under Inventory › Invoices › Tax groups.\",\n \"inventory.productForm.ncmHint\": \"The product's invoice classification. It belongs to the product, never to the group.\",\n \"inventory.productForm.icmsOrigin\": \"ICMS origin\",\n \"inventory.productForm.icmsRate\": \"ICMS rate (%)\",\n \"inventory.productForm.cstHint\": \"CST has 2 digits. CSOSN has 3 and is set on the tax group, for Simples Nacional.\",\n \"inventory.productForm.pisRate\": \"PIS rate (%)\",\n \"inventory.productForm.cofinsRate\": \"COFINS rate (%)\",\n \"inventory.productForm.baseCalcMode\": \"Tax base mode\",\n \"inventory.productForm.benefitCode\": \"Tax benefit code (cBenef)\",\n \"inventory.productForm.povertyFund\": \"Poverty fund (%)\",\n \"inventory.productForm.ibsCbsSituation\": \"IBS and CBS — tax situation\",\n \"inventory.productForm.ibsCbsClassification\": \"IBS and CBS — tax classification\",\n \"inventory.productForm.classificationRequired\": \"Pick at least one classification for the product.\",\n \"inventory.productType.ingredient\": \"Ingredient\",\n \"inventory.productType.sale\": \"For sale\",\n \"inventory.productType.intermediate\": \"Intermediate\",\n \"inventory.productType.asset\": \"Asset\",\n \"inventory.variants.tab\": \"Variants\",\n \"inventory.variants.name\": \"Variant\",\n \"inventory.variants.namePlaceholder\": \"E.g. M, L, XL, Blue\",\n \"inventory.variants.sku\": \"SKU\",\n \"inventory.variants.skuPlaceholder\": \"Optional\",\n \"inventory.variants.default\": \"Default\",\n \"inventory.variants.empty\": \"No variants. The product is sold and stocked as a single item.\",\n \"inventory.variants.duplicate\": \"A variant with this name already exists.\",\n \"inventory.variants.loadFailed\": \"Could not load the variants.\",\n \"inventory.variants.saveFailed\": \"Could not save the variant.\",\n \"inventory.variants.unavailable\": \"Variants are not available in this workspace.\",\n \"inventory.variants.onHand\": \"{{count}} in stock\",\n \"inventory.barcodes.tab\": \"Barcodes\",\n \"inventory.barcodes.code\": \"Barcode\",\n \"inventory.barcodes.codePlaceholder\": \"Type or scan\",\n \"inventory.barcodes.type\": \"Type\",\n \"inventory.barcodes.description\": \"Description\",\n \"inventory.barcodes.descriptionPlaceholder\": \"500 ml pack\",\n \"inventory.barcodes.needCode\": \"Type or scan a code.\",\n \"inventory.barcodes.empty\": \"No barcode registered.\",\n \"inventory.barcodes.duplicate\": \"This code is already in use.\",\n \"inventory.barcodes.isPrimary\": \"Primary — this is what the label prints\",\n \"inventory.barcodes.makePrimary\": \"Make primary\",\n \"inventory.barcodes.removeTitle\": \"Remove this barcode?\",\n \"inventory.barcodes.unavailable\": \"Barcodes are unavailable in this environment.\",\n \"inventory.productRecipe.tab\": \"Recipe\",\n \"inventory.productRecipe.none\": \"This product has no recipe yet.\",\n \"inventory.productRecipe.noneHint\": \"The recipe says what the product is made of — cost and food-cost come from it.\",\n \"inventory.productRecipe.goToRecipes\": \"Go to Recipes\",\n \"inventory.productForm.classificationUnset\": \"Unclassified\",\n \"inventory.productForm.stepIdentity\": \"Identity\",\n \"inventory.productForm.stepClassification\": \"Classification\",\n \"inventory.productForm.stepPricing\": \"Pricing\",\n \"inventory.productForm.stepStock\": \"Stock\",\n \"inventory.productForm.stepInitialEntry\": \"Opening stock\",\n \"inventory.productForm.initialEntrySection\": \"Receive stock\",\n \"inventory.productForm.initialEntrySectionDesc\": \"Optional: record what is already on the shelf. Leave blank to receive later.\",\n \"inventory.productForm.initialQuantity\": \"Quantity on hand\",\n \"inventory.productForm.initialLocation\": \"Location\",\n \"inventory.productForm.initialLocationHint\": \"Blank uses the product's default location.\",\n \"inventory.productForm.initialUnitCost\": \"Unit cost\",\n \"inventory.productForm.initialUnitCostHint\": \"Blank uses the product's cost.\",\n \"inventory.productForm.initialBatch\": \"Batch\",\n \"inventory.productForm.initialExpiry\": \"Expiry date\",\n \"inventory.productForm.initialEntryFailed\": \"Product created, but the stock entry was not recorded. Receive it from the Stock tab.\",\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 recipe...\",\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.\",\n \"inventory.counts.incomplete\": \"Finish the count before closing\",\n \"inventory.counts.incompleteDescription\": \"{{count}} line(s) are still blank. Enter zero when the item is physically out of stock.\",\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.badgePosted\": \"Posted\",\n \"inventory.usageAudit.badgeApproved\": \"Approved\",\n \"inventory.usageAudit.batchNoStock\": \"{count} without stock — still queued\",\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.periodLabel\": \"Period\",\n \"inventory.usageAudit.period30\": \"30 days\",\n \"inventory.usageAudit.period90\": \"90 days\",\n \"inventory.usageAudit.periodAll\": \"All time\",\n \"inventory.usageAudit.filterPending\": \"Pending\",\n \"inventory.usageAudit.emptyPending\": \"No usage waiting for review in this period.\",\n \"inventory.usageAudit.columnActions\": \"Actions\",\n \"inventory.usageAudit.post\": \"Post\",\n \"inventory.usageAudit.approve\": \"Approve\",\n \"inventory.usageAudit.postHint\": \"Accepts the usage AND deducts stock\",\n \"inventory.usageAudit.approveHint\": \"Accepts the usage without touching stock\",\n \"inventory.usageAudit.posted\": \"{{count}} line(s) posted to stock\",\n \"inventory.usageAudit.approved\": \"{{count}} line(s) approved\",\n \"inventory.usageAudit.approveFailed\": \"Could not accept the usage\",\n \"inventory.usageAudit.noStock\": \"No stock to post — receive the product or use Approve\",\n \"inventory.usageAudit.filtersLabel\": \"Filters\",\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 \"inventory.recipes.edit\": \"Edit\",\n \"inventory.recipes.print\": \"Print recipe\",\n \"inventory.recipes.printNoSheet\": \"No recipe to print\",\n \"inventory.recipes.pickTitle\": \"Select product\",\n \"inventory.recipes.pickHint\": \"Choose the product this recipe belongs to.\",\n \"inventory.recipes.pickPlaceholder\": \"Search product...\",\n \"inventory.recipes.pickContinue\": \"Continue\",\n \"inventory.sheet.name\": \"Recipe name\",\n \"inventory.sheet.namePlaceholder\": \"E.g. Grilled picanha\",\n \"inventory.sheet.nameRequired\": \"The recipe name is required.\",\n \"inventory.sheet.yield\": \"Yield\",\n \"inventory.sheet.yieldUnit\": \"Yield unit\",\n \"inventory.sheet.none\": \"None\",\n \"inventory.sheet.yieldMode\": \"Yield type\",\n \"inventory.sheet.yieldMode.portion\": \"Portion (the recipe is 1 unit sold)\",\n \"inventory.sheet.yieldMode.batch\": \"Batch (the recipe produces the yield)\",\n \"inventory.sheet.yieldMode.portionHint\": \"The yield only describes the plate («serves 4», «6 pieces», «400 g»). The product cost is the recipe total.\",\n \"inventory.sheet.yieldMode.batchHint\": \"The recipe produces the yield (e.g. 2.4 kg of sauce). The product cost is the recipe total ÷ the yield, in the product's unit.\",\n \"inventory.sheet.prepTime\": \"Prep time (min)\",\n \"inventory.sheet.description\": \"Description\",\n \"inventory.sheet.descriptionPlaceholder\": \"General description of the recipe\",\n \"inventory.sheet.costPrice\": \"Cost price\",\n \"inventory.sheet.per\": \"per\",\n \"inventory.sheet.batchCost\": \"Batch\",\n \"inventory.sheet.salePrice\": \"Sale price\",\n \"inventory.sheet.cmv\": \"Food cost\",\n \"inventory.sheet.components\": \"Recipe components (by station)\",\n \"inventory.sheet.suggestAi\": \"Suggest with AI\",\n \"inventory.sheet.addGroup\": \"Add group\",\n \"inventory.sheet.noComponents\": \"No components yet. Click \\\"Add group\\\" or use \\\"Suggest with AI\\\".\",\n \"inventory.sheet.componentName\": \"Component name\",\n \"inventory.sheet.componentNamePlaceholder\": \"E.g. Fried strips\",\n \"inventory.sheet.station\": \"Production station\",\n \"inventory.sheet.stationPlaceholder\": \"Select the station\",\n \"inventory.sheet.noStations\": \"No stations registered\",\n \"inventory.sheet.estimatedMinutes\": \"Estimated time (min)\",\n \"inventory.sheet.estimatedMinutesPlaceholder\": \"E.g. 20\",\n \"inventory.sheet.componentMenu\": \"More component actions\",\n \"inventory.sheet.transform\": \"Turn into intermediate product\",\n \"inventory.sheet.deleteComponent\": \"Delete component\",\n \"inventory.sheet.transformNeedsLines\": \"Add at least one ingredient to this component.\",\n \"inventory.sheet.noLines\": \"No ingredients. Click \\\"Add item\\\".\",\n \"inventory.sheet.ingredient\": \"Ingredient\",\n \"inventory.sheet.quantity\": \"Quantity\",\n \"inventory.sheet.notes\": \"Notes\",\n \"inventory.sheet.cost\": \"Cost\",\n \"inventory.sheet.unit\": \"Unit\",\n \"inventory.sheet.searchIngredient\": \"Search ingredient...\",\n \"inventory.sheet.createIngredient\": \"Create ingredient\",\n \"inventory.sheet.ingredientCreated\": \"Ingredient \\\"{{name}}\\\" created\",\n \"inventory.sheet.ingredientCreateFailed\": \"Could not create the ingredient.\",\n \"inventory.sheet.aiHint\": \"Suggested by AI\",\n \"inventory.sheet.create\": \"Create\",\n \"inventory.sheet.updateCost\": \"Update cost\",\n \"inventory.sheet.updateCostCurrent\": \"Update cost (now: {{price}}{{unit}})\",\n \"inventory.sheet.setCost\": \"Set the ingredient's cost\",\n \"inventory.sheet.removeLine\": \"Remove ingredient\",\n \"inventory.sheet.addLine\": \"Add item\",\n \"inventory.sheet.componentPrep\": \"How to prepare this component\",\n \"inventory.sheet.componentPrepPlaceholder\": \"How this component is prepared at the station\",\n \"inventory.sheet.outputs\": \"Production outputs (optional)\",\n \"inventory.sheet.outputsHint\": \"When this recipe yields more than one product (e.g. fillet + trimmings + skin). With no lines, production delivers only the main product. The order cost is split by each output's %; left blank, by market value. Waste carries no cost.\",\n \"inventory.sheet.addOutput\": \"Add output\",\n \"inventory.sheet.product\": \"Product\",\n \"inventory.sheet.outputType\": \"Type\",\n \"inventory.sheet.expectedQty\": \"Expected qty\",\n \"inventory.sheet.costShare\": \"% of cost\",\n \"inventory.sheet.auto\": \"auto\",\n \"inventory.sheet.removeOutput\": \"Remove output\",\n \"inventory.sheet.outputType.main\": \"Main\",\n \"inventory.sheet.outputType.coproduct\": \"Co-product\",\n \"inventory.sheet.outputType.byproduct\": \"By-product\",\n \"inventory.sheet.outputType.waste\": \"Waste\",\n \"inventory.sheet.outputShareTitle\": \"Check the outputs' % of cost\",\n \"inventory.sheet.outputShareHint\": \"Fill the % on every usable output, adding up to 100% — or leave them all blank to split by market value.\",\n \"inventory.sheet.instructions\": \"Assembly instructions (optional)\",\n \"inventory.sheet.instructionsPlaceholder\": \"How to assemble and finish the dish once the components are ready...\",\n \"inventory.sheet.save\": \"Save recipe\",\n \"inventory.sheet.saving\": \"Saving...\",\n \"inventory.sheet.saved\": \"Recipe saved\",\n \"inventory.sheet.saveFailed\": \"Could not save.\",\n \"inventory.sheet.loadFailed\": \"Could not load the recipe.\",\n \"inventory.sheet.costDialogTitle\": \"Update cost\",\n \"inventory.sheet.costDialogHint\": \"Set it by hand or ask the AI for a market estimate.\",\n \"inventory.sheet.costAppliesEverywhere\": \"The cost applies to every recipe that uses this ingredient.\",\n \"inventory.sheet.costInvalid\": \"Enter a value above zero.\",\n \"inventory.sheet.costUpdated\": \"{{name}} now costs {{price}}\",\n \"inventory.sheet.aiNoPrice\": \"The AI returned no price.\",\n \"inventory.sheet.aiFailed\": \"The AI did not answer. Try again.\",\n \"inventory.sheet.aiUnitMismatch\": \"The AI priced it per {{ai}}; this ingredient is counted in {{unit}}. Check before saving.\",\n \"inventory.sheet.aiTitle\": \"Suggest recipe with AI\",\n \"inventory.sheet.aiPhotos\": \"Product photos\",\n \"inventory.sheet.aiPhotosHint\": \"The more angles of the dish, the better the suggestion.\",\n \"inventory.sheet.aiProductName\": \"Product name\",\n \"inventory.sheet.aiStations\": \"Stations available to the AI:\",\n \"inventory.sheet.aiNoStations\": \"No stations registered — add stations so the AI can group correctly.\",\n \"inventory.sheet.aiInstructions\": \"Extra instructions for the AI (optional)\",\n \"inventory.sheet.aiInstructionsPlaceholder\": \"E.g. serves 2, gluten-free, use clarified butter, keep the sauce at the cold station...\",\n \"inventory.sheet.aiReplaces\": \"The suggestion replaces the components on the recipe. Nothing is saved until you save.\",\n \"inventory.sheet.aiGenerate\": \"Generate suggestion\",\n \"inventory.sheet.aiGenerating\": \"Generating...\",\n \"inventory.sheet.aiApplied\": \"Suggestion applied — review and save.\",\n \"inventory.sheet.uploadFailed\": \"Could not upload the image.\",\n \"inventory.sheet.addPhoto\": \"Add photo\",\n \"inventory.sheet.removePhoto\": \"Remove photo\",\n \"inventory.sheet.transformHint\": \"A new intermediate product is created with this block as its recipe. The block leaves this recipe — you can then add the intermediate as an item anywhere.\",\n \"inventory.sheet.transformName\": \"Intermediate product name\",\n \"inventory.sheet.transformNamePlaceholder\": \"E.g. White rice portion\",\n \"inventory.sheet.transformUnitPlaceholder\": \"Select (g, kg, ml, L, un...)\",\n \"inventory.sheet.transformNameRequired\": \"Enter the intermediate product's name.\",\n \"inventory.sheet.transformYieldRequired\": \"Enter the yield.\",\n \"inventory.sheet.transformUnitRequired\": \"Select the yield unit.\",\n \"inventory.sheet.transformDuplicate\": \"A product with this name already exists.\",\n \"inventory.sheet.transformCreate\": \"Create intermediate\",\n \"inventory.sheet.transformCreating\": \"Creating...\",\n \"inventory.sheet.transformDone\": \"\\\"{{name}}\\\" was created. You can now add it as an item to any component of this recipe.\",\n \"inventory.sheet.transformFailed\": \"Could not create the intermediate.\",\n \"inventory.complements.tab\": \"Add-ons\",\n \"inventory.complements.title\": \"Add-ons and choices\",\n \"inventory.complements.hint\": \"Set up flavours, doneness and extras. Use 0.00 when a choice costs nothing extra.\",\n \"inventory.complements.newGroup\": \"New group\",\n \"inventory.complements.empty\": \"This product has no add-ons yet.\",\n \"inventory.complements.emptyHint\": \"Create a group to start, like “Doneness” or “Whipped cream”.\",\n \"inventory.complements.groupName\": \"Group name\",\n \"inventory.complements.groupNamePlaceholder\": \"E.g. Doneness\",\n \"inventory.complements.active\": \"Active\",\n \"inventory.complements.moveUp\": \"Move group up\",\n \"inventory.complements.moveDown\": \"Move group down\",\n \"inventory.complements.deleteGroup\": \"Delete group\",\n \"inventory.complements.required\": \"Required choice\",\n \"inventory.complements.min\": \"Minimum\",\n \"inventory.complements.max\": \"Maximum\",\n \"inventory.complements.option\": \"Option\",\n \"inventory.complements.price\": \"Extra charge\",\n \"inventory.complements.optionActive\": \"Active\",\n \"inventory.complements.optionPlaceholder\": \"E.g. With whipped cream\",\n \"inventory.complements.deleteOption\": \"Delete option\",\n \"inventory.complements.addOption\": \"Add option\",\n \"inventory.complements.save\": \"Save add-ons\",\n \"inventory.complements.saved\": \"Add-ons saved\",\n \"inventory.complements.saveFailed\": \"Could not save\",\n \"inventory.complements.review\": \"Review the add-ons\",\n \"inventory.complements.loadFailed\": \"Could not load the add-ons\",\n \"inventory.photoAi.title\": \"Generate photo with AI\",\n \"inventory.photoAi.product\": \"Product\",\n \"inventory.photoAi.category\": \"Category\",\n \"inventory.photoAi.usesSheet\": \"The recipe's ingredients go into the photo's description.\",\n \"inventory.photoAi.references\": \"Reference images (optional)\",\n \"inventory.photoAi.useCurrent\": \"Use the current photo as reference\",\n \"inventory.photoAi.add\": \"Add\",\n \"inventory.photoAi.instructionsPlaceholder\": \"E.g. wooden table, late-afternoon light, served on a white plate...\",\n \"inventory.photoAi.generate\": \"Generate photo\",\n \"inventory.photoAi.again\": \"Generate another\",\n \"inventory.photoAi.generating\": \"Generating the photo…\",\n \"inventory.photoAi.apply\": \"Apply photo\",\n \"inventory.photoAi.applied\": \"Photo applied to the product\",\n \"inventory.photoAi.failed\": \"Could not generate the photo\",\n \"inventory.sheet.quickTitle\": \"New ingredient\",\n \"inventory.sheet.quickHint\": \"Registers the product as an ingredient and puts it on this line.\",\n \"inventory.sheet.quickName\": \"Name\",\n \"inventory.sheet.quickUnit\": \"Stock unit\",\n \"inventory.sheet.quickUnitHint\": \"Base unit used in recipes, stock and sales (e.g. un, ml, g).\",\n \"inventory.sheet.quickNameRequired\": \"Enter the ingredient's name.\",\n \"inventory.sheet.quickUnitRequired\": \"Choose the unit the ingredient is counted in.\",\n \"inventory.sheet.quickCreate\": \"Create ingredient\",\n \"inventory.recipes.pickEmpty\": \"No sold or intermediate product found.\",\n \"inventory.recipes.kind.sale\": \"Sold\",\n \"inventory.recipes.kind.intermediate\": \"Intermediate\",\n \"inventory.recipes.kind.produced\": \"Produced\",\n \"inventory.recipes.kind.all\": \"All\",\n \"inventory.recipes.hasSheet\": \"Has recipe\",\n \"inventory.recipes.noSheetShort\": \"No recipe\",\n}\n","// inventory.* — merged plugin-own + saas-core central i18n\nexport const ptBR: Record<string, string> = {\n \"inventory.nav.panel\": \"Painel\",\n \"inventory.panel.columnProduct\": \"Produto\",\n \"inventory.panel.columnLocation\": \"Local\",\n \"inventory.panel.columnBatch\": \"Lote\",\n \"inventory.panel.columnExpiry\": \"Validade\",\n \"inventory.panel.columnQuantity\": \"Qtd / mín.\",\n \"inventory.panel.columnValue\": \"Valor\",\n \"inventory.panel.empty\": \"Nenhuma posição de estoque para este recorte.\",\n \"inventory.panel.totalLines\": \"Linhas\",\n \"inventory.panel.totalValue\": \"Valor em estoque\",\n \"inventory.panel.unsupported\": \"Este aplicativo não expõe o painel de estoque.\",\n \"inventory.filters.stockState\": \"Status do estoque\",\n \"inventory.filters.health.negative\": \"Negativo\",\n \"inventory.filters.health.below_min\": \"Abaixo do mín.\",\n \"inventory.filters.health.zero\": \"Zerado\",\n \"inventory.filters.health.ok\": \"OK\",\n \"inventory.filters.expiry\": \"Validade\",\n \"inventory.filters.expiry.all\": \"Todas\",\n \"inventory.filters.expiry.expired\": \"Vencidos\",\n \"inventory.filters.expiry.le30\": \"Vence em 30 dias\",\n \"inventory.filters.expiry.le60\": \"Vence em 60 dias\",\n \"inventory.filters.expiry.le90\": \"Vence em 90 dias\",\n \"inventory.filters.expiry.none\": \"Sem validade\",\n \"inventory.filters.batchPlaceholder\": \"Lote\",\n \"inventory.filters.productPlaceholder\": \"Buscar produto...\",\n \"inventory.filters.countState\": \"Situação da contagem\",\n \"inventory.filters.countAll\": \"Todas\",\n \"inventory.filters.countPending\": \"A contar\",\n \"inventory.filters.countDone\": \"Contadas\",\n \"inventory.filters.itemSearchPlaceholder\": \"Buscar produto ou código...\",\n \"inventory.filters.title\": \"Filtros\",\n \"inventory.filters.apply\": \"Buscar\",\n \"inventory.filters.pending\": \"Filtros alterados\",\n \"inventory.filters.pendingHint\": \"A lista ainda mostra o recorte anterior. Clique em Buscar para aplicar.\",\n \"inventory.filters.clear\": \"Limpar\",\n \"inventory.filters.more\": \"Mais filtros\",\n \"inventory.filters.less\": \"Menos filtros\",\n \"inventory.filters.from\": \"De\",\n \"inventory.filters.to\": \"Até\",\n \"inventory.filters.allTypes\": \"Todos os tipos\",\n \"inventory.filters.location\": \"Local\",\n \"inventory.filters.allLocations\": \"Todos os locais\",\n \"inventory.filters.category\": \"Categoria\",\n \"inventory.filters.allCategories\": \"Todas as categorias\",\n \"inventory.filters.kind\": \"Tipo de item\",\n \"inventory.filters.allKinds\": \"Todos\",\n \"inventory.filters.status\": \"Situação\",\n \"inventory.filters.allStatuses\": \"Todas\",\n \"inventory.stock.pendingRetry\": \"A confirmação ainda está pendente. Não faça outro lançamento. Tente novamente com os mesmos dados antes de sair desta tela.\",\n \"inventory.stock.refreshAfterCommit\": \"Movimento registrado. Atualize a tela para consultar o saldo.\",\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\": \"Fichas Técnicas\",\n \"inventory.entity.stockLocation\": \"Local de Estoque\",\n \"inventory.entity.stockLocation.plural\": \"Locais de Estoque\",\n \"inventory.entity.productCategory\": \"Categoria\",\n \"inventory.entity.productCategory.plural\": \"Categorias\",\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\": \"Resumo\",\n \"inventory.nav.entry\": \"Entrada\",\n \"inventory.nav.exit\": \"Saída\",\n \"inventory.nav.history\": \"Histórico\",\n \"inventory.nav.inventory\": \"Inventário\",\n \"inventory.nav.list\": \"Lista\",\n \"inventory.nav.new\": \"Novo\",\n \"inventory.nav.products\": \"Produtos\",\n \"inventory.nav.stock\": \"Movimentações\",\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 Ficha Técnica\",\n \"inventory.recipes.noRecipes\": \"Nenhum produto produzido ainda\",\n \"inventory.recipes.exporting\": \"Gerando a planilha das fichas…\",\n \"inventory.recipes.exported\": \"Planilha baixada\",\n \"inventory.sheet.print\": \"Imprimir\",\n \"inventory.sheet.printSaveFirst\": \"Salve a ficha antes de imprimir\",\n \"inventory.recipes.noCategory\": \"Sem categoria\",\n \"inventory.recipes.filterKind\": \"Tipo\",\n \"inventory.recipes.filterKindAll\": \"Todos os tipos\",\n \"inventory.recipes.kindSale\": \"Venda\",\n \"inventory.recipes.kindIntermediate\": \"Intermediário\",\n \"inventory.recipes.filterCategory\": \"Categoria\",\n \"inventory.recipes.filterCategoryAll\": \"Todas as categorias\",\n \"inventory.recipes.filterCmv\": \"CMV\",\n \"inventory.recipes.filterCmvAll\": \"Todo CMV\",\n \"inventory.recipes.cmvHigh\": \"CMV acima de {{pct}}%\",\n \"inventory.recipes.cmvGood\": \"CMV bom (abaixo de {{pct}}%)\",\n \"inventory.recipes.cmvAttention\": \"CMV atenção ({{from}}–{{to}}%)\",\n \"inventory.recipes.cmvNone\": \"Sem CMV\",\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\": \"Fichas Técnicas\",\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.minimum\": \"Mínimo\",\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.modules\": \"Módulos\",\n \"inventory.settings.modulesDesc\": \"O que desta casa aparece no Estoque\",\n \"inventory.settings.recipes\": \"Receitas\",\n \"inventory.settings.recipesDesc\": \"A ficha técnica que diz quanto cada produto consome\",\n \"inventory.settings.requisitions\": \"Requisições\",\n \"inventory.settings.requisitionsDesc\": \"Pedidos internos de material entre setores\",\n \"inventory.settings.usageAuditDesc\": \"O que saiu do estoque contra o que foi vendido\",\n \"inventory.settings.temperature\": \"Temperatura\",\n \"inventory.settings.temperatureDesc\": \"Registro de temperatura dos locais refrigerados\",\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 // As fichas do produto — portadas do cadastro do V1 (as abas por tipo).\n \"inventory.productForm.commissionPercent\": \"% Comissão (venda)\",\n \"inventory.productForm.commissionPercentHint\": \"Quanto o profissional ganha ao vender este produto.\",\n \"inventory.productForm.chartAccount\": \"Plano de Contas\",\n \"inventory.productForm.avgPurchasePrice\": \"Preço médio de compra\",\n \"inventory.productForm.avgPurchasePriceHint\": \"Atualizado a cada entrada de estoque.\",\n \"inventory.productForm.packaging\": \"Embalagem e Conversões\",\n \"inventory.productForm.packagingDesc\": \"Como a casa compra, quando é diferente de como ela conta.\",\n \"inventory.productForm.contentPerUnit\": \"Conteúdo por Unidade\",\n \"inventory.productForm.contentPerUnitHint\": \"Quanto cabe em UMA unidade de estoque (um frasco contém 300 ml).\",\n \"inventory.productForm.contentUnit\": \"Unidade de Conteúdo\",\n \"inventory.productForm.purchaseUnit\": \"Unidade de Compra\",\n \"inventory.productForm.conversionFactor\": \"Quantidade por Embalagem\",\n \"inventory.productForm.conversionFactorHint\": \"Quantas unidades de estoque vêm em uma unidade de compra.\",\n \"inventory.productForm.flagIngredient\": \"Insumo\",\n \"inventory.productForm.flagIngredientHint\": \"Aparece nas fichas técnicas.\",\n \"inventory.productForm.flagForSale\": \"Venda\",\n \"inventory.productForm.flagForSaleHint\": \"Cardápio, PDV, catálogo.\",\n \"inventory.productForm.flagIntermediate\": \"Intermediário\",\n \"inventory.productForm.flagIntermediateHint\": \"Produzido para consumir depois (molho, massa).\",\n \"inventory.productForm.flagAsset\": \"Patrimônio\",\n \"inventory.productForm.flagAssetHint\": \"Equipamento: entra no balanço, não se consome.\",\n \"inventory.productForm.flagProduced\": \"Produto produzido\",\n \"inventory.productForm.flagProducedHint\": \"Nasce de uma receita — habilita a ficha técnica.\",\n \"inventory.productForm.flagResale\": \"Revenda\",\n \"inventory.productForm.flagResaleHint\": \"Mercadoria destinada à revenda ao cliente.\",\n \"inventory.productForm.flagTracked\": \"Alto custo / etiquetado\",\n \"inventory.productForm.flagTrackedHint\": \"Cada unidade é acompanhada individualmente.\",\n \"inventory.productForm.professionalResalePrice\": \"Preço de revenda profissional\",\n \"inventory.productForm.professionalResalePriceHint\": \"Preço cobrado quando o profissional revende ao cliente final.\",\n \"inventory.productForm.requireBatch\": \"Exigir lote na entrada\",\n \"inventory.productForm.requireBatchHint\": \"Bloqueia entrada de estoque sem número de lote.\",\n \"inventory.productForm.requireExpiry\": \"Exigir validade na entrada\",\n \"inventory.productForm.requireExpiryHint\": \"Bloqueia entrada de estoque sem data de validade.\",\n \"inventory.productForm.notes\": \"Observações\",\n \"inventory.productForm.ingredientSection\": \"Insumo\",\n \"inventory.productForm.ingredientSectionDesc\": \"O que a compra precisa saber para repor na hora certa.\",\n \"inventory.productForm.ingReorderPoint\": \"Ponto de reposição\",\n \"inventory.productForm.ingReorderPointHint\": \"Fica ACIMA do mínimo: é o aviso que ainda chega a tempo de comprar.\",\n \"inventory.productForm.ingLeadTime\": \"Prazo de entrega (dias)\",\n \"inventory.productForm.ingShelfLife\": \"Validade (dias)\",\n \"inventory.productForm.ingStorageTemp\": \"Temperatura de armazenamento\",\n \"inventory.productForm.saleSection\": \"Venda\",\n \"inventory.productForm.saleSectionDesc\": \"O que o cardápio e o balcão mostram ao cliente.\",\n \"inventory.productForm.salePrepTime\": \"Tempo de preparo (min)\",\n \"inventory.productForm.saleServes\": \"Serve (pessoas)\",\n \"inventory.productForm.saleCalories\": \"Calorias (kcal)\",\n \"inventory.productForm.saleMenuDescription\": \"Descrição no cardápio\",\n \"inventory.productForm.saleAllergens\": \"Alergênicos\",\n \"inventory.productForm.saleAllergensPlaceholder\": \"Contém glúten, lactose\",\n \"inventory.productForm.saleSoldByWeight\": \"Vendido por peso\",\n \"inventory.productForm.saleHighlightDelivery\": \"Destacar no delivery\",\n \"inventory.productForm.saleAvailableDelivery\": \"Disponível no delivery\",\n \"inventory.productForm.saleAvailableCounter\": \"Disponível no balcão\",\n \"inventory.productForm.saleChannelsSection\": \"Preços por canal\",\n \"inventory.productForm.saleChannelsSectionDesc\": \"Deixe vazio o canal que usa o preço de venda base.\",\n \"inventory.productForm.intermediateSection\": \"Intermediário\",\n \"inventory.productForm.intermediateSectionDesc\": \"O que a produção precisa saber para preparar o lote.\",\n \"inventory.productForm.intYield\": \"Rendimento (%)\",\n \"inventory.productForm.intPrepTime\": \"Tempo de preparo (min)\",\n \"inventory.productForm.intShelfLifeHours\": \"Validade após preparo (h)\",\n \"inventory.productForm.intBatchSize\": \"Tamanho do lote\",\n \"inventory.productForm.intBatchUnit\": \"Unidade do lote\",\n \"inventory.productForm.intStorage\": \"Instruções de armazenamento\",\n \"inventory.productForm.assetSection\": \"Patrimônio\",\n \"inventory.productForm.assetSectionDesc\": \"O equipamento que a casa possui, e quem responde por ele.\",\n \"inventory.productForm.assetValue\": \"Valor do ativo\",\n \"inventory.productForm.assetResidualValue\": \"Valor residual\",\n \"inventory.productForm.assetUsefulLife\": \"Vida útil (meses)\",\n \"inventory.productForm.assetDepreciation\": \"Depreciação anual (%)\",\n \"inventory.productForm.assetSerial\": \"Número de série\",\n \"inventory.productForm.assetAcquisition\": \"Data de aquisição\",\n \"inventory.productForm.assetWarranty\": \"Garantia até\",\n \"inventory.productForm.assetStatus\": \"Situação\",\n \"inventory.productForm.assetLocation\": \"Localização\",\n \"inventory.productForm.assetLocationPlaceholder\": \"Sala 2, prateleira B\",\n \"inventory.productForm.assetResponsible\": \"Responsável\",\n \"inventory.productForm.assetInsurance\": \"Apólice de seguro\",\n \"inventory.productForm.assetLastMaintenance\": \"Última manutenção\",\n \"inventory.productForm.assetNextMaintenance\": \"Próxima manutenção\",\n \"inventory.productForm.taxSection\": \"Fiscal\",\n \"inventory.productForm.taxSectionDesc\": \"O que a nota precisa dizer sobre este produto. Em branco vale o que o grupo fiscal diz.\",\n \"inventory.productForm.taxGroup\": \"Grupo fiscal\",\n \"inventory.productForm.taxGroupHint\": \"Cadastre em Estoque › Notas Fiscais › Grupos Fiscais.\",\n \"inventory.productForm.ncmHint\": \"Classificação do produto na nota. É do produto, nunca do grupo.\",\n \"inventory.productForm.icmsOrigin\": \"ICMS de origem\",\n \"inventory.productForm.icmsRate\": \"Alíquota ICMS (%)\",\n \"inventory.productForm.cstHint\": \"CST tem 2 dígitos. CSOSN tem 3 e se configura no grupo fiscal, para o Simples Nacional.\",\n \"inventory.productForm.pisRate\": \"Alíquota PIS (%)\",\n \"inventory.productForm.cofinsRate\": \"Alíquota COFINS (%)\",\n \"inventory.productForm.baseCalcMode\": \"Modalidade de base de cálculo\",\n \"inventory.productForm.benefitCode\": \"Código de benefícios fiscais (cBenef)\",\n \"inventory.productForm.povertyFund\": \"Fundo de combate à pobreza (%)\",\n \"inventory.productForm.ibsCbsSituation\": \"IBS e CBS — situação tributária\",\n \"inventory.productForm.ibsCbsClassification\": \"IBS e CBS — classificação tributária\",\n \"inventory.productForm.classificationRequired\": \"Escolha ao menos uma classificação para o produto.\",\n \"inventory.productType.ingredient\": \"Insumo\",\n \"inventory.productType.sale\": \"Venda\",\n \"inventory.productType.intermediate\": \"Intermediário\",\n \"inventory.productType.asset\": \"Patrimônio\",\n \"inventory.variants.tab\": \"Variações\",\n \"inventory.variants.name\": \"Variação\",\n \"inventory.variants.namePlaceholder\": \"Ex.: M, G, GG, Azul\",\n \"inventory.variants.sku\": \"SKU\",\n \"inventory.variants.skuPlaceholder\": \"Opcional\",\n \"inventory.variants.default\": \"Padrão\",\n \"inventory.variants.empty\": \"Nenhuma variação. O produto é vendido e estocado como um item só.\",\n \"inventory.variants.duplicate\": \"Já existe uma variação com esse nome.\",\n \"inventory.variants.loadFailed\": \"Não foi possível carregar as variações.\",\n \"inventory.variants.saveFailed\": \"Não foi possível salvar a variação.\",\n \"inventory.variants.unavailable\": \"Variações não estão disponíveis nesta conta.\",\n \"inventory.variants.onHand\": \"{{count}} em estoque\",\n \"inventory.barcodes.tab\": \"Códigos de Barras\",\n \"inventory.barcodes.code\": \"Código de barras\",\n \"inventory.barcodes.codePlaceholder\": \"Digite ou bipe\",\n \"inventory.barcodes.type\": \"Tipo\",\n \"inventory.barcodes.description\": \"Descrição\",\n \"inventory.barcodes.descriptionPlaceholder\": \"Embalagem 500 ml\",\n \"inventory.barcodes.needCode\": \"Digite ou bipe um código.\",\n \"inventory.barcodes.empty\": \"Nenhum código de barras cadastrado.\",\n \"inventory.barcodes.duplicate\": \"Este código já está em uso.\",\n \"inventory.barcodes.isPrimary\": \"Principal — é o que a etiqueta imprime\",\n \"inventory.barcodes.makePrimary\": \"Tornar principal\",\n \"inventory.barcodes.removeTitle\": \"Remover este código de barras?\",\n \"inventory.barcodes.unavailable\": \"Códigos de barras indisponíveis neste ambiente.\",\n \"inventory.productRecipe.tab\": \"Ficha Técnica\",\n \"inventory.productRecipe.none\": \"Este produto ainda não tem ficha técnica.\",\n \"inventory.productRecipe.noneHint\": \"A ficha técnica diz de que o produto é feito — é dela que saem o custo e o CMV.\",\n \"inventory.productRecipe.goToRecipes\": \"Ir para Receitas\",\n \"inventory.productForm.classificationUnset\": \"Sem classificação\",\n \"inventory.productForm.stepIdentity\": \"Identificação\",\n \"inventory.productForm.stepClassification\": \"Classificação\",\n \"inventory.productForm.stepPricing\": \"Preço\",\n \"inventory.productForm.stepStock\": \"Estoque\",\n \"inventory.productForm.stepInitialEntry\": \"Entrada inicial\",\n \"inventory.productForm.initialEntrySection\": \"Dar entrada no estoque\",\n \"inventory.productForm.initialEntrySectionDesc\": \"Opcional: registre o que já está na prateleira. Deixe em branco para dar entrada depois.\",\n \"inventory.productForm.initialQuantity\": \"Quantidade em estoque\",\n \"inventory.productForm.initialLocation\": \"Local\",\n \"inventory.productForm.initialLocationHint\": \"Em branco usa o local padrão do produto.\",\n \"inventory.productForm.initialUnitCost\": \"Custo unitário\",\n \"inventory.productForm.initialUnitCostHint\": \"Em branco usa o custo do produto.\",\n \"inventory.productForm.initialBatch\": \"Lote\",\n \"inventory.productForm.initialExpiry\": \"Validade\",\n \"inventory.productForm.initialEntryFailed\": \"Produto criado, mas a entrada de estoque não foi registrada. Dê entrada pela aba Estoque.\",\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 receita...\",\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.\",\n \"inventory.counts.incomplete\": \"Finalize a contagem antes de fechar\",\n \"inventory.counts.incompleteDescription\": \"Ainda existem {{count}} linha(s) em branco. Informe zero quando o item acabou fisicamente.\",\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.badgePosted\": \"Baixado\",\n \"inventory.usageAudit.badgeApproved\": \"Aprovado\",\n \"inventory.usageAudit.batchNoStock\": \"{count} sem saldo — seguem na fila\",\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.periodLabel\": \"Período\",\n \"inventory.usageAudit.period30\": \"30 dias\",\n \"inventory.usageAudit.period90\": \"90 dias\",\n \"inventory.usageAudit.periodAll\": \"Todo o período\",\n \"inventory.usageAudit.filterPending\": \"Pendentes\",\n \"inventory.usageAudit.emptyPending\": \"Nenhum consumo esperando conferência neste período.\",\n \"inventory.usageAudit.columnActions\": \"Ações\",\n \"inventory.usageAudit.post\": \"Baixar\",\n \"inventory.usageAudit.approve\": \"Aprovar\",\n \"inventory.usageAudit.postHint\": \"Aceita o consumo E desconta do saldo\",\n \"inventory.usageAudit.approveHint\": \"Aceita o consumo sem mexer no saldo\",\n \"inventory.usageAudit.posted\": \"{{count}} linha(s) baixada(s) do estoque\",\n \"inventory.usageAudit.approved\": \"{{count}} linha(s) aprovada(s)\",\n \"inventory.usageAudit.approveFailed\": \"Não foi possível aceitar o consumo\",\n \"inventory.usageAudit.noStock\": \"Sem saldo para baixar — dê entrada no produto ou use Aprovar\",\n \"inventory.usageAudit.filtersLabel\": \"Filtros\",\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 \"inventory.recipes.edit\": \"Editar\",\n \"inventory.recipes.print\": \"Imprimir ficha técnica\",\n \"inventory.recipes.printNoSheet\": \"Sem ficha técnica para imprimir\",\n \"inventory.recipes.pickTitle\": \"Selecionar Produto\",\n \"inventory.recipes.pickHint\": \"Escolha o produto ao qual esta ficha técnica será associada.\",\n \"inventory.recipes.pickPlaceholder\": \"Buscar produto...\",\n \"inventory.recipes.pickContinue\": \"Continuar\",\n \"inventory.sheet.name\": \"Nome da Ficha Técnica\",\n \"inventory.sheet.namePlaceholder\": \"Ex: Picanha na Chapa\",\n \"inventory.sheet.nameRequired\": \"O nome da ficha técnica é obrigatório.\",\n \"inventory.sheet.yield\": \"Rendimento\",\n \"inventory.sheet.yieldUnit\": \"Unidade Rendimento\",\n \"inventory.sheet.none\": \"Nenhuma\",\n \"inventory.sheet.yieldMode\": \"Tipo de rendimento\",\n \"inventory.sheet.yieldMode.portion\": \"Porção (a ficha é 1 unidade vendida)\",\n \"inventory.sheet.yieldMode.batch\": \"Lote (a ficha produz o rendimento)\",\n \"inventory.sheet.yieldMode.portionHint\": \"O rendimento só descreve o que vai no prato («para 4 pessoas», «6 unidades», «400 g»). O custo do produto é a soma da ficha.\",\n \"inventory.sheet.yieldMode.batchHint\": \"A ficha produz o rendimento informado (ex.: 2,4 kg de molho). O custo do produto é a soma da ficha ÷ o rendimento, na unidade do produto.\",\n \"inventory.sheet.prepTime\": \"Tempo Preparo (min)\",\n \"inventory.sheet.description\": \"Descrição Geral\",\n \"inventory.sheet.descriptionPlaceholder\": \"Descrição geral da ficha técnica\",\n \"inventory.sheet.costPrice\": \"Preço de Custo\",\n \"inventory.sheet.per\": \"por\",\n \"inventory.sheet.batchCost\": \"Lote\",\n \"inventory.sheet.salePrice\": \"Preço de Venda\",\n \"inventory.sheet.cmv\": \"CMV\",\n \"inventory.sheet.components\": \"Componentes da Ficha Técnica (por estação)\",\n \"inventory.sheet.suggestAi\": \"Sugerir com IA\",\n \"inventory.sheet.addGroup\": \"Adicionar Grupo\",\n \"inventory.sheet.noComponents\": \"Nenhum componente adicionado. Clique em \\\"Adicionar Grupo\\\" ou use \\\"Sugerir com IA\\\".\",\n \"inventory.sheet.componentName\": \"Nome do Componente\",\n \"inventory.sheet.componentNamePlaceholder\": \"Ex: Porção de Iscas\",\n \"inventory.sheet.station\": \"Estação de Produção\",\n \"inventory.sheet.stationPlaceholder\": \"Selecione a estação\",\n \"inventory.sheet.noStations\": \"Nenhuma estação cadastrada\",\n \"inventory.sheet.estimatedMinutes\": \"Tempo estimado (min)\",\n \"inventory.sheet.estimatedMinutesPlaceholder\": \"Ex: 20\",\n \"inventory.sheet.componentMenu\": \"Mais ações do componente\",\n \"inventory.sheet.transform\": \"Transformar em produto intermediário\",\n \"inventory.sheet.deleteComponent\": \"Excluir componente\",\n \"inventory.sheet.transformNeedsLines\": \"Adicione ao menos um insumo neste componente.\",\n \"inventory.sheet.noLines\": \"Nenhum insumo. Clique em \\\"Adicionar Item\\\".\",\n \"inventory.sheet.ingredient\": \"Insumo\",\n \"inventory.sheet.quantity\": \"Quantidade\",\n \"inventory.sheet.notes\": \"Obs\",\n \"inventory.sheet.cost\": \"Custo\",\n \"inventory.sheet.unit\": \"Unidade\",\n \"inventory.sheet.searchIngredient\": \"Buscar insumo...\",\n \"inventory.sheet.createIngredient\": \"Criar insumo\",\n \"inventory.sheet.ingredientCreated\": \"Insumo \\\"{{name}}\\\" criado\",\n \"inventory.sheet.ingredientCreateFailed\": \"Não foi possível criar o insumo.\",\n \"inventory.sheet.aiHint\": \"Sugerido pela IA\",\n \"inventory.sheet.create\": \"Criar\",\n \"inventory.sheet.updateCost\": \"Atualizar custo\",\n \"inventory.sheet.updateCostCurrent\": \"Atualizar custo (atual: {{price}}{{unit}})\",\n \"inventory.sheet.setCost\": \"Definir preço de custo do insumo\",\n \"inventory.sheet.removeLine\": \"Remover insumo\",\n \"inventory.sheet.addLine\": \"Adicionar Item\",\n \"inventory.sheet.componentPrep\": \"Modo de Preparo deste Componente\",\n \"inventory.sheet.componentPrepPlaceholder\": \"Como preparar este componente na estação\",\n \"inventory.sheet.outputs\": \"Saídas da produção (opcional)\",\n \"inventory.sheet.outputsHint\": \"Quando esta ficha gera mais de um produto (ex.: filé + aparas + pele). Sem linhas aqui, a produção entrega apenas o produto principal com o rendimento da ficha. O custo da OP é dividido pelo % de cada saída; em branco, pelo valor de mercado (preço médio de compra × quantidade). Rejeito não leva custo.\",\n \"inventory.sheet.addOutput\": \"Adicionar saída\",\n \"inventory.sheet.product\": \"Produto\",\n \"inventory.sheet.outputType\": \"Tipo\",\n \"inventory.sheet.expectedQty\": \"Qtd esperada\",\n \"inventory.sheet.costShare\": \"% do custo\",\n \"inventory.sheet.auto\": \"auto\",\n \"inventory.sheet.removeOutput\": \"Remover saída\",\n \"inventory.sheet.outputType.main\": \"Principal\",\n \"inventory.sheet.outputType.coproduct\": \"Coproduto\",\n \"inventory.sheet.outputType.byproduct\": \"Subproduto\",\n \"inventory.sheet.outputType.waste\": \"Descarte\",\n \"inventory.sheet.outputShareTitle\": \"Confira o % do custo das saídas\",\n \"inventory.sheet.outputShareHint\": \"Preencha o % em todas as saídas aproveitáveis, somando 100% — ou deixe todas em branco para ratear pelo valor de mercado.\",\n \"inventory.sheet.instructions\": \"Modo de Preparo Geral / Montagem (opcional)\",\n \"inventory.sheet.instructionsPlaceholder\": \"Como montar e finalizar o prato após os componentes prontos...\",\n \"inventory.sheet.save\": \"Salvar Ficha Técnica\",\n \"inventory.sheet.saving\": \"Salvando...\",\n \"inventory.sheet.saved\": \"Ficha técnica salva\",\n \"inventory.sheet.saveFailed\": \"Não foi possível salvar.\",\n \"inventory.sheet.loadFailed\": \"Não foi possível carregar a ficha técnica.\",\n \"inventory.sheet.costDialogTitle\": \"Atualizar custo\",\n \"inventory.sheet.costDialogHint\": \"Defina manualmente ou peça uma sugestão à IA com base no mercado.\",\n \"inventory.sheet.costAppliesEverywhere\": \"O custo vale para todas as fichas que usam este insumo.\",\n \"inventory.sheet.costInvalid\": \"Informe um valor maior que zero.\",\n \"inventory.sheet.costUpdated\": \"{{name}} agora custa {{price}}\",\n \"inventory.sheet.aiNoPrice\": \"A IA não retornou um preço.\",\n \"inventory.sheet.aiFailed\": \"A IA não respondeu. Tente novamente.\",\n \"inventory.sheet.aiUnitMismatch\": \"A IA deu o preço por {{ai}}; este insumo é contado em {{unit}}. Confira antes de salvar.\",\n \"inventory.sheet.aiTitle\": \"Sugerir Ficha Técnica com IA\",\n \"inventory.sheet.aiPhotos\": \"Fotos do produto\",\n \"inventory.sheet.aiPhotosHint\": \"Quanto mais ângulos do prato, melhor a sugestão.\",\n \"inventory.sheet.aiProductName\": \"Nome do produto\",\n \"inventory.sheet.aiStations\": \"Estações disponíveis para a IA:\",\n \"inventory.sheet.aiNoStations\": \"Nenhuma estação cadastrada — cadastre estações para a IA agrupar corretamente.\",\n \"inventory.sheet.aiInstructions\": \"Instruções adicionais para a IA (opcional)\",\n \"inventory.sheet.aiInstructionsPlaceholder\": \"Ex.: Porção para 2 pessoas, sem glúten, usar manteiga clarificada, separar molho em estação fria...\",\n \"inventory.sheet.aiReplaces\": \"A sugestão substitui os componentes que estão na ficha. Nada é gravado até você salvar.\",\n \"inventory.sheet.aiGenerate\": \"Gerar sugestão\",\n \"inventory.sheet.aiGenerating\": \"Gerando...\",\n \"inventory.sheet.aiApplied\": \"Sugestão aplicada — confira e salve.\",\n \"inventory.sheet.uploadFailed\": \"Não foi possível enviar a imagem.\",\n \"inventory.sheet.addPhoto\": \"Adicionar foto\",\n \"inventory.sheet.removePhoto\": \"Remover foto\",\n \"inventory.sheet.transformHint\": \"Será criado um novo produto do tipo intermediário com esta ficha técnica (ingredientes e modo de preparo). O bloco atual será removido daqui — depois você pode adicionar este intermediário em qualquer etapa.\",\n \"inventory.sheet.transformName\": \"Nome do Produto Intermediário\",\n \"inventory.sheet.transformNamePlaceholder\": \"Ex: Arroz Branco Porção\",\n \"inventory.sheet.transformUnitPlaceholder\": \"Selecione (g, kg, ml, L, un...)\",\n \"inventory.sheet.transformNameRequired\": \"Informe o nome do produto intermediário.\",\n \"inventory.sheet.transformYieldRequired\": \"Informe o rendimento.\",\n \"inventory.sheet.transformUnitRequired\": \"Selecione a unidade de medida do rendimento.\",\n \"inventory.sheet.transformDuplicate\": \"Já existe um produto com este nome.\",\n \"inventory.sheet.transformCreate\": \"Criar Intermediário\",\n \"inventory.sheet.transformCreating\": \"Criando...\",\n \"inventory.sheet.transformDone\": \"\\\"{{name}}\\\" foi cadastrado. Agora você pode adicioná-lo como item em qualquer componente desta ficha técnica.\",\n \"inventory.sheet.transformFailed\": \"Falha ao transformar em intermediário.\",\n \"inventory.complements.tab\": \"Complementos\",\n \"inventory.complements.title\": \"Complementos e escolhas\",\n \"inventory.complements.hint\": \"Configure sabores, pontos de preparo e adicionais. Use R$ 0,00 quando a escolha não tiver acréscimo.\",\n \"inventory.complements.newGroup\": \"Novo grupo\",\n \"inventory.complements.empty\": \"Este produto ainda não possui complementos.\",\n \"inventory.complements.emptyHint\": \"Crie um grupo para começar, como “Ponto da carne” ou “Chantilly”.\",\n \"inventory.complements.groupName\": \"Nome do grupo\",\n \"inventory.complements.groupNamePlaceholder\": \"Ex: Ponto da carne\",\n \"inventory.complements.active\": \"Ativo\",\n \"inventory.complements.moveUp\": \"Mover grupo para cima\",\n \"inventory.complements.moveDown\": \"Mover grupo para baixo\",\n \"inventory.complements.deleteGroup\": \"Excluir grupo\",\n \"inventory.complements.required\": \"Escolha obrigatória\",\n \"inventory.complements.min\": \"Mínimo\",\n \"inventory.complements.max\": \"Máximo\",\n \"inventory.complements.option\": \"Opção\",\n \"inventory.complements.price\": \"Acréscimo\",\n \"inventory.complements.optionActive\": \"Ativa\",\n \"inventory.complements.optionPlaceholder\": \"Ex: Com chantilly\",\n \"inventory.complements.deleteOption\": \"Excluir opção\",\n \"inventory.complements.addOption\": \"Adicionar opção\",\n \"inventory.complements.save\": \"Salvar complementos\",\n \"inventory.complements.saved\": \"Complementos salvos\",\n \"inventory.complements.saveFailed\": \"Não foi possível salvar\",\n \"inventory.complements.review\": \"Revise os complementos\",\n \"inventory.complements.loadFailed\": \"Não foi possível carregar os complementos\",\n \"inventory.photoAi.title\": \"Gerar foto com IA\",\n \"inventory.photoAi.product\": \"Produto\",\n \"inventory.photoAi.category\": \"Categoria\",\n \"inventory.photoAi.usesSheet\": \"Os insumos da ficha técnica entram na descrição da foto.\",\n \"inventory.photoAi.references\": \"Imagens de referência (opcional)\",\n \"inventory.photoAi.useCurrent\": \"Usar foto atual do produto como referência\",\n \"inventory.photoAi.add\": \"Adicionar\",\n \"inventory.photoAi.instructionsPlaceholder\": \"Ex.: fundo de madeira, luz de fim de tarde, porção servida em prato branco...\",\n \"inventory.photoAi.generate\": \"Gerar foto\",\n \"inventory.photoAi.again\": \"Gerar outra\",\n \"inventory.photoAi.generating\": \"Gerando a foto…\",\n \"inventory.photoAi.apply\": \"Aplicar foto\",\n \"inventory.photoAi.applied\": \"Foto aplicada ao produto\",\n \"inventory.photoAi.failed\": \"Não foi possível gerar a foto\",\n \"inventory.sheet.quickTitle\": \"Novo insumo\",\n \"inventory.sheet.quickHint\": \"Cadastra o produto como Insumo e o coloca nesta linha.\",\n \"inventory.sheet.quickName\": \"Nome\",\n \"inventory.sheet.quickUnit\": \"Unidade de Estoque\",\n \"inventory.sheet.quickUnitHint\": \"Unidade base usada em ficha técnica, estoque e vendas (ex: un, ml, g).\",\n \"inventory.sheet.quickNameRequired\": \"Informe o nome do insumo.\",\n \"inventory.sheet.quickUnitRequired\": \"Escolha a unidade em que o insumo é contado.\",\n \"inventory.sheet.quickCreate\": \"Criar insumo\",\n \"inventory.recipes.pickEmpty\": \"Nenhum produto de venda ou intermediário encontrado.\",\n \"inventory.recipes.kind.sale\": \"Venda\",\n \"inventory.recipes.kind.intermediate\": \"Intermediário\",\n \"inventory.recipes.kind.produced\": \"Produzido\",\n \"inventory.recipes.kind.all\": \"Todos\",\n \"inventory.recipes.hasSheet\": \"Com ficha\",\n \"inventory.recipes.noSheetShort\": \"Sem ficha\",\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","import React from 'react'\nimport type { DetailTab, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { UNIT_DETAIL_ZONES } from '@fayz-ai/admin'\nimport { createInventoryDashboardWidgets } from './views/dashboardWidgets'\nimport type { ResolvedInventoryConfig } from './context'\nimport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nimport type { StockMovement } from '@fayz-ai/inventory/domain/movement'\nimport { lazyComponent, registerTranslations } from '@fayz-ai/core'\nimport { PluginSettingsPanel } from '@fayz-ai/admin'\nimport { createInventoryDataProvider, createInventoryStore } from '@fayz-ai/inventory/store'\nimport { inventoryRegistries } from './data/registries'\nimport { inventorySetupGuides } from './lib/setup-guides'\nimport { buildInventoryOnboarding } from './lib/onboarding'\nimport { inventoryLocales } from './locales'\nimport { upsertRecipeTool } from './lib/agent-tools'\nimport { MIGRATIONS } from './migrations'\n\n// Code loads when it is first drawn, not with the app. Pages use React.lazy\n// (the shell's route boundary shows the page skeleton); anything that may\n// render elsewhere uses lazyComponent, which carries its own boundary.\nconst InventoryPage = React.lazy(() => import('./views/InventoryPage').then((m) => ({ default: m.InventoryPage })))\nconst UnitStockLocationsWidget = lazyComponent(() => import('./views/UnitStockLocationsWidget').then((m) => m.UnitStockLocationsWidget))\nconst InventoryGeneralSettings = lazyComponent(() => import('./components/InventoryGeneralSettings').then((m) => m.InventoryGeneralSettings))\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\n/** Uma tela que outro plugin empresta ao Estoque. */\nexport interface InventoryExtraView {\n /** Vira o segmento da URL: `/inventory/<id>`. Em inglês, como toda rota do V2. */\n id: string\n label: string\n icon?: string\n render: () => React.ReactNode\n /**\n * Telas irmãs sob a mesma aba, como o V1 agrupa cinco sob «Notas Fiscais».\n * Sem isto, quatro telas de nota virariam quatro abas no Estoque e afogariam\n * Produtos e Movimentações.\n */\n children?: Array<{ id: string; label: string; render: () => React.ReactNode }>\n /**\n * O nome da PRÓPRIA tela quando ela entra como primeiro filho do grupo. Sem\n * isto o Estoque chamava toda tela emprestada de «Entrada», que era o nome de\n * uma delas — e o grupo de notas quis o nome do V1, «Manifesto de Notas».\n */\n defaultChildLabel?: string\n}\n\nexport interface InventoryNavShortcut {\n /** The inner view id; the entry routes to `/inventory/<view>`. */\n view: string\n label: string\n icon?: string\n /** Defaults to inventory read. A borrowed view (fiscal notes) passes its own. */\n permission?: { feature: string; action: 'read' }\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 /**\n * Telas que OUTRO plugin contribui para dentro do Estoque, como abas irmãs de\n * Produtos, Movimentações e Contagens.\n *\n * Existe porque «Entrada de Notas» é assunto de estoque e não assunto do rail:\n * no V1 o caminho é `Estoque → Notas Fiscais → Entrada de Notas`, e montá-la\n * como linha solta no menu quebra o mapa mental de quem vem do V1 — a pessoa\n * procura dentro do Estoque e não acha. Quem dá entrada de nota é o\n * `plugin-fiscal-br`, que não pode reivindicar uma aba do Estoque sem esta\n * porta.\n *\n * A ordem na faixa é a ordem deste array, depois das abas próprias.\n */\n extraViews?: InventoryExtraView[]\n /**\n * Inner views the app also wants as direct rail entries under Estoque\n * (e.g. `products-list`, `inbound-notes`). Opt-in: without it the module is\n * one rail row and every screen lives in its own tab strip.\n */\n navShortcuts?: InventoryNavShortcut[]\n /**\n * Tabs another plugin contributes to the product record — the shop's photos,\n * say. The catalog product is this plugin's; what else is known about it is\n * not, so the app composes it here instead of this plugin importing theirs.\n * Shown after the plugin's own tabs.\n */\n productDetailTabs?: DetailTab[]\n /**\n * O documento que originou um movimento de estoque — a nota de entrada, hoje —\n * desenhado dentro do modal que o Estoque abre. Ver `ResolvedInventoryConfig`.\n */\n documentModal?: (movement: StockMovement, close: () => void) => React.ReactNode\n scope?: PluginScope\n /**\n * Como o Estoque desenha a PRÓPRIA navegação (Produtos, Movimentações,\n * Contagens, Receitas).\n *\n * O padrão vem do shell, e num app cujo default é `sidebar` esse padrão diz\n * \"o rail lista as minhas sub-telas\" — promessa que ninguém cumpre por este\n * módulo: no rail ele é UMA linha, e o que tem dentro é tela irmã, não\n * assunto novo. O resultado era o Estoque abrindo sem faixa de abas nenhuma.\n *\n * Mesma porta que `crm`, `marketing` e `financial` já usam.\n */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\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', labelKey: 'inventory.productType.ingredient' },\n { value: 'sale', label: 'For Sale', labelKey: 'inventory.productType.sale' },\n { value: 'intermediate', label: 'Intermediate', labelKey: 'inventory.productType.intermediate' },\n { value: 'asset', label: 'Asset', labelKey: 'inventory.productType.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 moduleNav: options?.moduleNav,\n extraViews: options?.extraViews ?? [],\n productDetailTabs: options?.productDetailTabs ?? [],\n documentModal: options?.documentModal,\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 ?? 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 // Como esta conta refaz o módulo com as opções DELA. Ver PluginRebuild:\n // a fábrica roda no carregamento do aplicativo, muito antes de a\n // configuração da conta existir, e sem isto `app.tenant_plugins.config`\n // não tinha como chegar aqui. A fusão é RASA e por bloco — a conta troca\n // `modules` inteiro ou não o troca —, que é o mesmo contrato que a chamada\n // do aplicativo já tem.\n rebuild: (tenantConfig) =>\n createInventoryPlugin({ ...options, ...(tenantConfig as InventoryPluginOptions) }),\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 // The shell nests these under `/inventory` by route prefix, and only when\n // the parent sorts first — a lower position would leave them top-level.\n ...(options?.navShortcuts ?? []).map((shortcut, i) => ({\n section: options?.navSection ?? 'main',\n position: (options?.navPosition ?? 4) + (i + 1) / 100,\n label: shortcut.label,\n route: `/inventory/${shortcut.view}`,\n icon: shortcut.icon,\n permission: shortcut.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 {\n id: 'inventory-unit-stock-locations',\n zone: UNIT_DETAIL_ZONES.stockLocations,\n component: UnitStockLocationsWidget as unknown as React.ComponentType<unknown>,\n order: 0,\n },\n ],\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: 'Quais produtos estão com estoque baixo?' },\n { label: 'Quais insumos precisam de reposição?', verticalId: 'food' as const },\n { label: 'Mostre um resumo do estoque' },\n { label: 'Quais são os produtos mais usados?' },\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, { config }),\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 { createInventoryDataProvider }\nexport type { InventoryDataProvider } from '@fayz-ai/inventory/data/provider'\nexport type { ResolvedInventoryConfig } from './context'\n\nexport {\n MOVEMENT_TYPES,\n MOVEMENT_TYPE_VALUES,\n LEGACY_PT_MOVEMENT_TYPE,\n movementTypeSpec,\n normalizeMovementType,\n} from '@fayz-ai/inventory/domain/movement'\nexport type { MovementType, MovementTypeSpec } from '@fayz-ai/inventory/domain/movement'\nexport type {\n ConsumeRecipeForSourceInput,\n ReverseRecipeConsumptionInput,\n InventoryConsumptionResult,\n InventoryConsumptionStatus,\n InventoryConsumptionSkipReason,\n} from '@fayz-ai/inventory/domain/consumption'\n"]}
|