@fayz-ai/plugin-inventory 0.16.0 → 0.16.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"registries.d.ts","sourceRoot":"","sources":["../../src/data/registries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAmGtD,eAAO,MAAM,mBAAmB,EAAE,iBAAiB,EAuClD,CAAA"}
1
+ {"version":3,"file":"registries.d.ts","sourceRoot":"","sources":["../../src/data/registries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAsGtD,eAAO,MAAM,mBAAmB,EAAE,iBAAiB,EAuClD,CAAA"}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import React6, { useMemo, useState, useEffect, useCallback, useRef } from 'react';
2
- import { toast, defineKpiWidget, defineCustomWidget, PageTransition, ComingSoon, ModulePage, Button, FilterPanel, FilterPanelField, RequiredFilter, FilterMenuRow, SubpageHeader, SearchSelect, cn, DatePicker, InlineLink, ListView, Modal, ModalContent, Card, Input, DataTable, SegmentedControl, ConfirmDialog, Badge, DraftCommitBar, Switch, TooltipProvider, PageHeaderActions, DashboardCanvas, Thumbnail, Skeleton, CurrencyInput, ModalHeader, ModalTitle, ModalBody, Checkbox, ModalFooter, AiActionButton, ModalDescription, Tooltip, TooltipTrigger, TooltipContent, CardContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, StockEntryForm, useSaveBar, Dropdown, DropdownTrigger, DropdownContent, DropdownItem, DropdownSeparator, openPrintWindow, printDocument, createXlsxReport, KpiCard, CardHeader, CardTitle } from '@fayz-ai/ui';
1
+ import React14, { useMemo, useState, useEffect, useCallback, useRef } from 'react';
2
+ import { toast, defineKpiWidget, defineCustomWidget, PageTransition, ComingSoon, ModulePage, Button, FilterPanel, FilterPanelField, RequiredFilter, FilterMenuRow, SubpageHeader, SearchSelect, cn, DatePicker, InlineLink, ListView, Modal, ModalContent, Card, Input, DataTable, SegmentedControl, ConfirmDialog, Badge, DraftCommitBar, Switch, TooltipProvider, PageHeaderActions, DashboardCanvas, Thumbnail, ModalHeader, ModalTitle, ModalBody, Checkbox, ModalFooter, AiActionButton, ModalDescription, Tooltip, TooltipTrigger, TooltipContent, CardContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, StockEntryForm, Skeleton, CurrencyInput, openPrintWindow, printDocument, createXlsxReport, useSaveBar, Dropdown, DropdownTrigger, DropdownContent, DropdownItem, DropdownSeparator, KpiCard, CardHeader, CardTitle } from '@fayz-ai/ui';
3
3
  import { createPluginContext, UNIT_DETAIL_ZONES, PluginSettingsPanel, dedup, RelatedListTab, useModuleNavigation, usePluginOnboardingGate, PluginOnboardingGateSkeleton, createViewRouter, RegistryCrudView, ModuleActionBar, useTenantPluginSettings, SettingsGroup, ToggleRow, useOrganizationStore, usePermissionOptional, CrudListView, useLimitGuard, invalidateRelationOptions, CrudFormSkeleton, CrudFormPage, CrudDetailPage, formatCurrency, resolveDocumentOpenerFor, useRememberedList, usePersistedState, useScrollMemory, useAgentSurface, PageActions, useOfferedPlugins, invalidateLimit, RecordPickerModal } from '@fayz-ai/admin';
4
4
  import { recordRailFields, RECORD_GROUP, activeFacet, createSafeDataProvider, registerTranslations, tl, countByTenant, useTranslation, getActiveUnitId, createPendingCommand, emitDataChanged, getSupabaseClientOptional, getActiveTenantId, errorMessage } from '@fayz-ai/core';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
- import { Trash2, ArrowRightLeft, RefreshCw, ArrowUpRight, ArrowDownRight, Package, Ruler, MapPin, Loader2, Check, ChevronRight, CircleSlash, CircleCheck, Boxes, Layers, CircleDashed, Search, ListFilter, CalendarRange, PackageCheck, ClipboardCheck, AlertTriangle, Plus, ArrowUp, ArrowDown, Sparkles, X, Upload, Building2, Utensils, Clock, Printer, Pencil, Star, Undo2, MoreVertical, PackageX } from 'lucide-react';
6
+ import { Trash2, ArrowRightLeft, RefreshCw, ArrowUpRight, ArrowDownRight, Package, Ruler, MapPin, Loader2, Check, ChevronRight, CircleSlash, CircleCheck, Boxes, Layers, CircleDashed, Search, ListFilter, CalendarRange, PackageCheck, ClipboardCheck, AlertTriangle, Plus, Sparkles, X, Upload, Building2, Utensils, Clock, Printer, Pencil, Star, Undo2, ArrowUp, ArrowDown, MoreVertical, PackageX } from 'lucide-react';
7
7
  import { createStore as createStore$1 } from 'zustand/vanilla';
8
8
 
9
9
  // src/index.ts
@@ -1767,7 +1767,7 @@ function inventoryModuleDefaults(verticalId) {
1767
1767
  }
1768
1768
  function useInventoryHouseModules() {
1769
1769
  const verticalId = useOrganizationStore((state) => state.currentOrg?.verticalId);
1770
- const defaults = React6.useMemo(() => inventoryModuleDefaults(verticalId), [verticalId]);
1770
+ const defaults = React14.useMemo(() => inventoryModuleDefaults(verticalId), [verticalId]);
1771
1771
  return useTenantPluginSettings("inventory", defaults);
1772
1772
  }
1773
1773
  var INVENTORY_DEFAULTS = {
@@ -1834,145 +1834,6 @@ function useHasMenu() {
1834
1834
  function useHasRecipes() {
1835
1835
  return useInventoryHouseModules().get("recipes");
1836
1836
  }
1837
- function ProductCrudForm({ editId, onSaved }) {
1838
- const t2 = useTranslation();
1839
- const { productTypes, currency } = useInventoryConfig();
1840
- const provider = useInventoryProvider();
1841
- const createProduct = useInventoryStore((s) => s.createProduct);
1842
- const guardProducts = useLimitGuard("products");
1843
- const isEdit = !!editId;
1844
- const [initialData, setInitialData] = React6.useState(isEdit ? null : {});
1845
- const [headerName, setHeaderName] = React6.useState("");
1846
- const [referenceDataReady, setReferenceDataReady] = React6.useState(false);
1847
- React6.useEffect(() => {
1848
- let cancelled = false;
1849
- (async () => {
1850
- try {
1851
- await provider.ensureReferenceData?.();
1852
- invalidateRelationOptions();
1853
- } catch (error) {
1854
- console.warn("[inventory] Could not prepare reference data", error);
1855
- } finally {
1856
- if (!cancelled) setReferenceDataReady(true);
1857
- }
1858
- })();
1859
- return () => {
1860
- cancelled = true;
1861
- };
1862
- }, [provider]);
1863
- React6.useEffect(() => {
1864
- if (!editId) return;
1865
- let cancelled = false;
1866
- (async () => {
1867
- const p = await provider.getProductById(editId);
1868
- if (cancelled) return;
1869
- setHeaderName(p?.name ?? "");
1870
- setInitialData(p ? flattenProduct(p) : {});
1871
- })();
1872
- return () => {
1873
- cancelled = true;
1874
- };
1875
- }, [editId]);
1876
- const hasMenu = useHasMenu();
1877
- const hasRecipes = useHasRecipes();
1878
- const entity = React6.useMemo(
1879
- () => buildProductEntity(t2, productTypes, currency, void 0, provider, true, hasMenu, hasRecipes),
1880
- [t2, productTypes, currency, provider, hasMenu, hasRecipes]
1881
- );
1882
- async function save(values) {
1883
- const name = String(values.name ?? "").trim();
1884
- if (!name) {
1885
- toast.error(t2("common.formIncomplete"));
1886
- throw new Error("name required");
1887
- }
1888
- const classification = {
1889
- isIngredient: values.isIngredient === true,
1890
- isForSale: values.isForSale === true,
1891
- isIntermediate: values.isIntermediate === true,
1892
- isAsset: values.isAsset === true,
1893
- isProduced: values.isProduced === true,
1894
- isResale: values.isResale === true,
1895
- trackByUnitLabel: values.trackByUnitLabel === true
1896
- };
1897
- if (!Object.values(classification).some(Boolean)) {
1898
- toast.error(t2("inventory.productForm.classificationRequired"));
1899
- throw new Error("classification required");
1900
- }
1901
- const productType = values.productType ?? productTypes[0]?.value;
1902
- const payload = {
1903
- classification,
1904
- extras: {
1905
- commissionPercent: Number(values.commissionPercent) || 0,
1906
- chartAccountId: values.chartAccountId ?? "",
1907
- contentPerUnit: values.contentPerUnit === "" ? void 0 : Number(values.contentPerUnit) || void 0,
1908
- contentUnitId: values.contentUnitId ?? "",
1909
- avgPurchasePrice: Number(values.avgPurchasePrice) || void 0,
1910
- professionalResalePrice: Number(values.professionalResalePrice) || void 0,
1911
- requireBatchForStock: values.requireBatchForStock === true,
1912
- requireExpiryForStock: values.requireExpiryForStock === true
1913
- },
1914
- ...toFichas(values),
1915
- purchaseUnitId: values.purchaseUnitId ?? "",
1916
- conversionFactor: Number(values.conversionFactor) || 1,
1917
- name,
1918
- sku: values.sku || void 0,
1919
- barcode: values.barcode || void 0,
1920
- brand: values.brand || void 0,
1921
- productType,
1922
- costPrice: Number(values.costPrice) || 0,
1923
- // Switching a menu item back to an input must clear the old commercial
1924
- // price as well as hide it; otherwise reports would keep treating the
1925
- // ingredient as sellable even though the form no longer showed why.
1926
- salePrice: classification.isForSale ? Number(values.salePrice) || void 0 : 0,
1927
- minQuantity: Number(values.minQuantity) || 0,
1928
- maxQuantity: Number(values.maxQuantity) || void 0,
1929
- description: values.description || void 0,
1930
- // Always sent, even when empty: an empty string clears the link, and
1931
- // `undefined` would leave the previous value in place on edit.
1932
- categoryId: values.categoryId ?? "",
1933
- measurementUnitId: values.measurementUnitId ?? "",
1934
- supplierId: values.supplierId ?? "",
1935
- defaultLocationId: values.defaultLocationId ?? ""
1936
- };
1937
- const imageFile = typeof File !== "undefined" && values._imageFile instanceof File ? values._imageFile : void 0;
1938
- if (isEdit && editId) {
1939
- await provider.updateProduct(editId, payload);
1940
- if (imageFile && provider.uploadProductImage) await provider.uploadProductImage(editId, imageFile);
1941
- } else {
1942
- if (await guardProducts() === "blocked") return;
1943
- const created = await createProduct(payload);
1944
- if (imageFile && provider.uploadProductImage) {
1945
- try {
1946
- await provider.uploadProductImage(created.id, imageFile);
1947
- } catch (error) {
1948
- toast.error("Produto criado, mas a foto n\xE3o foi enviada.", {
1949
- description: errorMessage(error)
1950
- });
1951
- }
1952
- }
1953
- invalidateLimit("products");
1954
- }
1955
- onSaved?.();
1956
- }
1957
- const title = isEdit ? headerName || t2("inventory.productForm.editProduct") : t2("inventory.productForm.newProduct");
1958
- const subtitle = isEdit ? void 0 : t2("inventory.productForm.addToCatalog");
1959
- return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
1960
- /* @__PURE__ */ jsx(SubpageHeader, { title, subtitle, onBack: onSaved, parentLabel: t2("inventory.nav.products") }),
1961
- (!initialData || !referenceDataReady) && /* @__PURE__ */ jsx(CrudFormSkeleton, { hideBreadcrumb: true }),
1962
- initialData && referenceDataReady && /* @__PURE__ */ jsx(
1963
- CrudFormPage,
1964
- {
1965
- entityDef: entity,
1966
- mode: isEdit ? "edit" : "create",
1967
- initialData,
1968
- onSubmit: save,
1969
- onCancel: () => onSaved?.(),
1970
- namePlural: t2("inventory.nav.products"),
1971
- hideBreadcrumb: true
1972
- }
1973
- )
1974
- ] });
1975
- }
1976
1837
 
1977
1838
  // src/lib/recipe-units.ts
1978
1839
  var FAMILY_BY_ABBR = {
@@ -3137,13 +2998,14 @@ var SHEET_LAYOUT = `
3137
2998
  .rs-comp{grid-template-columns:minmax(0,1fr) minmax(0,1fr) 9rem auto}
3138
2999
  .rs-comp>*:not(.rs-comp-menu){grid-column:auto}
3139
3000
  .rs-comp>.rs-comp-menu{grid-column:4}
3001
+ .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}
3002
+ .rs-line>*{grid-column:auto !important}
3003
+ .rs-line>:nth-child(4){justify-content:flex-end}
3140
3004
  }
3141
3005
  @container (min-width: 60rem){
3142
3006
  .rs-head{grid-template-columns:minmax(0,2.2fr) repeat(4,minmax(0,1fr))}
3143
3007
  .rs-head>.rs-name{grid-column:auto}
3144
- .rs-line,.rs-line-head{display:grid;grid-template-columns:minmax(0,2fr) 200px minmax(0,1.4fr) 120px 36px;align-items:center;gap:.75rem;border:0;padding:0}
3145
- .rs-line>*{grid-column:auto !important}
3146
- .rs-line>:nth-child(4){justify-content:flex-end}
3008
+ .rs-line,.rs-line-head{grid-template-columns:minmax(0,2fr) 200px minmax(0,1.4fr) 120px 36px;gap:.75rem}
3147
3009
  .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}
3148
3010
  }
3149
3011
  `;
@@ -3557,6 +3419,19 @@ function DetailSkeleton() {
3557
3419
  /* @__PURE__ */ jsx("div", { className: "rounded-card border p-4 space-y-2", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx("div", { className: "h-3.5 rounded bg-muted/30 animate-pulse" }, i)) })
3558
3420
  ] });
3559
3421
  }
3422
+ function productRecordTabs({ entity, flat, hasMenu, hasRecipes, withComplements, initialTab, contributedTabs, t: t2, reload }) {
3423
+ const extra = [];
3424
+ if (hasMenu && flat?.isForSale && withComplements) {
3425
+ extra.push({ id: "complements", label: t2("inventory.complements.tab"), icon: "ListPlus", component: ProductComplementsTab });
3426
+ }
3427
+ if (hasRecipes && (flat?.isProduced || initialTab === "recipe")) {
3428
+ extra.push({ id: "recipe", label: t2("inventory.productRecipe.tab"), icon: "ChefHat", component: ProductRecipeTab, props: { onChanged: reload } });
3429
+ }
3430
+ const tabs = entity.detailTabs ?? [];
3431
+ const stockAt = tabs.findIndex((tab) => tab.id === "stock");
3432
+ const own = stockAt < 0 ? [...tabs, ...extra] : [...tabs.slice(0, stockAt), ...extra, ...tabs.slice(stockAt)];
3433
+ return [...own, ...contributedTabs];
3434
+ }
3560
3435
  function ProductDetailView({ productId, initialTab, onBack, onEdit }) {
3561
3436
  const t2 = useTranslation();
3562
3437
  const { currency, productTypes, productDetailTabs: contributedTabs } = useInventoryConfig();
@@ -3593,17 +3468,7 @@ function ProductDetailView({ productId, initialTab, onBack, onEdit }) {
3593
3468
  }, [provider, productId, reload, flat]);
3594
3469
  const [photoOpen, setPhotoOpen] = useState(false);
3595
3470
  const entityForDetail = useMemo(() => {
3596
- const extra = [];
3597
- if (hasMenu && flat?.isForSale && provider.getProductOptionGroups) {
3598
- extra.push({ id: "complements", label: t2("inventory.complements.tab"), icon: "ListPlus", component: ProductComplementsTab });
3599
- }
3600
- if (hasRecipes && (flat?.isProduced || initialTab === "recipe")) {
3601
- extra.push({ id: "recipe", label: t2("inventory.productRecipe.tab"), icon: "ChefHat", component: ProductRecipeTab, props: { onChanged: reload } });
3602
- }
3603
- const tabs = entity.detailTabs ?? [];
3604
- const stockAt = tabs.findIndex((tab) => tab.id === "stock");
3605
- const own = stockAt < 0 ? [...tabs, ...extra] : [...tabs.slice(0, stockAt), ...extra, ...tabs.slice(stockAt)];
3606
- const detailTabs = [...own, ...contributedTabs];
3471
+ const detailTabs = productRecordTabs({ entity, flat, hasMenu, hasRecipes, withComplements: Boolean(provider.getProductOptionGroups), initialTab, contributedTabs, t: t2, reload });
3607
3472
  return {
3608
3473
  ...entity,
3609
3474
  detailTabs,
@@ -3649,6 +3514,154 @@ function ProductDetailView({ productId, initialTab, onBack, onEdit }) {
3649
3514
  photoOpen && /* @__PURE__ */ jsx(GenerateImageDialog, { product, onClose: () => setPhotoOpen(false), onApplied: reload })
3650
3515
  ] });
3651
3516
  }
3517
+ function ProductCrudForm({ editId, onSaved, onOpenTab }) {
3518
+ const t2 = useTranslation();
3519
+ const { productTypes, currency, productDetailTabs: contributedTabs } = useInventoryConfig();
3520
+ const provider = useInventoryProvider();
3521
+ const createProduct = useInventoryStore((s) => s.createProduct);
3522
+ const guardProducts = useLimitGuard("products");
3523
+ const isEdit = !!editId;
3524
+ const [initialData, setInitialData] = React14.useState(isEdit ? null : {});
3525
+ const [headerName, setHeaderName] = React14.useState("");
3526
+ const [referenceDataReady, setReferenceDataReady] = React14.useState(false);
3527
+ React14.useEffect(() => {
3528
+ let cancelled = false;
3529
+ (async () => {
3530
+ try {
3531
+ await provider.ensureReferenceData?.();
3532
+ invalidateRelationOptions();
3533
+ } catch (error) {
3534
+ console.warn("[inventory] Could not prepare reference data", error);
3535
+ } finally {
3536
+ if (!cancelled) setReferenceDataReady(true);
3537
+ }
3538
+ })();
3539
+ return () => {
3540
+ cancelled = true;
3541
+ };
3542
+ }, [provider]);
3543
+ React14.useEffect(() => {
3544
+ if (!editId) return;
3545
+ let cancelled = false;
3546
+ (async () => {
3547
+ const p = await provider.getProductById(editId);
3548
+ if (cancelled) return;
3549
+ setHeaderName(p?.name ?? "");
3550
+ setInitialData(p ? flattenProduct(p) : {});
3551
+ })();
3552
+ return () => {
3553
+ cancelled = true;
3554
+ };
3555
+ }, [editId]);
3556
+ const hasMenu = useHasMenu();
3557
+ const hasRecipes = useHasRecipes();
3558
+ const entity = React14.useMemo(
3559
+ () => buildProductEntity(t2, productTypes, currency, void 0, provider, true, hasMenu, hasRecipes),
3560
+ [t2, productTypes, currency, provider, hasMenu, hasRecipes]
3561
+ );
3562
+ async function save(values) {
3563
+ const name = String(values.name ?? "").trim();
3564
+ if (!name) {
3565
+ toast.error(t2("common.formIncomplete"));
3566
+ throw new Error("name required");
3567
+ }
3568
+ const classification = {
3569
+ isIngredient: values.isIngredient === true,
3570
+ isForSale: values.isForSale === true,
3571
+ isIntermediate: values.isIntermediate === true,
3572
+ isAsset: values.isAsset === true,
3573
+ isProduced: values.isProduced === true,
3574
+ isResale: values.isResale === true,
3575
+ trackByUnitLabel: values.trackByUnitLabel === true
3576
+ };
3577
+ if (!Object.values(classification).some(Boolean)) {
3578
+ toast.error(t2("inventory.productForm.classificationRequired"));
3579
+ throw new Error("classification required");
3580
+ }
3581
+ const productType = values.productType ?? productTypes[0]?.value;
3582
+ const payload = {
3583
+ classification,
3584
+ extras: {
3585
+ commissionPercent: Number(values.commissionPercent) || 0,
3586
+ chartAccountId: values.chartAccountId ?? "",
3587
+ contentPerUnit: values.contentPerUnit === "" ? void 0 : Number(values.contentPerUnit) || void 0,
3588
+ contentUnitId: values.contentUnitId ?? "",
3589
+ avgPurchasePrice: Number(values.avgPurchasePrice) || void 0,
3590
+ professionalResalePrice: Number(values.professionalResalePrice) || void 0,
3591
+ requireBatchForStock: values.requireBatchForStock === true,
3592
+ requireExpiryForStock: values.requireExpiryForStock === true
3593
+ },
3594
+ ...toFichas(values),
3595
+ purchaseUnitId: values.purchaseUnitId ?? "",
3596
+ conversionFactor: Number(values.conversionFactor) || 1,
3597
+ name,
3598
+ sku: values.sku || void 0,
3599
+ barcode: values.barcode || void 0,
3600
+ brand: values.brand || void 0,
3601
+ productType,
3602
+ costPrice: Number(values.costPrice) || 0,
3603
+ // Switching a menu item back to an input must clear the old commercial
3604
+ // price as well as hide it; otherwise reports would keep treating the
3605
+ // ingredient as sellable even though the form no longer showed why.
3606
+ salePrice: classification.isForSale ? Number(values.salePrice) || void 0 : 0,
3607
+ minQuantity: Number(values.minQuantity) || 0,
3608
+ maxQuantity: Number(values.maxQuantity) || void 0,
3609
+ description: values.description || void 0,
3610
+ // Always sent, even when empty: an empty string clears the link, and
3611
+ // `undefined` would leave the previous value in place on edit.
3612
+ categoryId: values.categoryId ?? "",
3613
+ measurementUnitId: values.measurementUnitId ?? "",
3614
+ supplierId: values.supplierId ?? "",
3615
+ defaultLocationId: values.defaultLocationId ?? ""
3616
+ };
3617
+ const imageFile = typeof File !== "undefined" && values._imageFile instanceof File ? values._imageFile : void 0;
3618
+ if (isEdit && editId) {
3619
+ await provider.updateProduct(editId, payload);
3620
+ if (imageFile && provider.uploadProductImage) await provider.uploadProductImage(editId, imageFile);
3621
+ } else {
3622
+ if (await guardProducts() === "blocked") return;
3623
+ const created = await createProduct(payload);
3624
+ if (imageFile && provider.uploadProductImage) {
3625
+ try {
3626
+ await provider.uploadProductImage(created.id, imageFile);
3627
+ } catch (error) {
3628
+ toast.error("Produto criado, mas a foto n\xE3o foi enviada.", {
3629
+ description: errorMessage(error)
3630
+ });
3631
+ }
3632
+ }
3633
+ invalidateLimit("products");
3634
+ }
3635
+ onSaved?.();
3636
+ }
3637
+ const formEntity = React14.useMemo(() => {
3638
+ if (!isEdit || !initialData) return entity;
3639
+ return {
3640
+ ...entity,
3641
+ detailTabs: productRecordTabs({ entity, flat: initialData, hasMenu, hasRecipes, withComplements: Boolean(provider.getProductOptionGroups), contributedTabs, t: t2 })
3642
+ };
3643
+ }, [entity, isEdit, initialData, hasMenu, hasRecipes, provider, contributedTabs, t2]);
3644
+ const ready = Boolean(initialData) && referenceDataReady;
3645
+ const title = isEdit ? headerName || t2("inventory.productForm.editProduct") : t2("inventory.productForm.newProduct");
3646
+ const subtitle = isEdit ? void 0 : t2("inventory.productForm.addToCatalog");
3647
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
3648
+ (!isEdit || !ready) && /* @__PURE__ */ jsx(SubpageHeader, { title, subtitle, onBack: onSaved, parentLabel: t2("inventory.nav.products") }),
3649
+ !ready && /* @__PURE__ */ jsx(CrudFormSkeleton, { twoColumn: true, tabs: isEdit }),
3650
+ ready && /* @__PURE__ */ jsx(
3651
+ CrudFormPage,
3652
+ {
3653
+ entityDef: formEntity,
3654
+ mode: isEdit ? "edit" : "create",
3655
+ initialData,
3656
+ onSubmit: save,
3657
+ onCancel: () => onSaved?.(),
3658
+ namePlural: t2("inventory.nav.products"),
3659
+ hideBreadcrumb: !isEdit,
3660
+ onRecordTab: isEdit ? onOpenTab : void 0
3661
+ }
3662
+ )
3663
+ ] });
3664
+ }
3652
3665
  function signedQuantity(q) {
3653
3666
  const n = Number(q) || 0;
3654
3667
  return n > 0 ? `+${n}` : String(n);
@@ -5838,7 +5851,7 @@ function parseQuantity(raw) {
5838
5851
  if (!Number.isFinite(parsed) || parsed < 0) return void 0;
5839
5852
  return parsed;
5840
5853
  }
5841
- var CountedField = React6.memo(function CountedField2({
5854
+ var CountedField = React14.memo(function CountedField2({
5842
5855
  entry,
5843
5856
  value,
5844
5857
  onChange,
@@ -6628,7 +6641,7 @@ function InventoryPage({ config: appConfig, provider, store, registries }) {
6628
6641
  "products-recipe": 1,
6629
6642
  settings: 1
6630
6643
  }, "dashboard");
6631
- const checkExistingData = React6.useCallback(
6644
+ const checkExistingData = React14.useCallback(
6632
6645
  async () => (await provider.getProducts({ pageSize: 1 })).total > 0,
6633
6646
  [provider]
6634
6647
  );
@@ -6641,7 +6654,7 @@ function InventoryPage({ config: appConfig, provider, store, registries }) {
6641
6654
  temperature: houseModules.get("temperature"),
6642
6655
  hiddenViews: houseModules.get("hiddenViews")
6643
6656
  });
6644
- const completeOnboarding = React6.useCallback(async () => {
6657
+ const completeOnboarding = React14.useCallback(async () => {
6645
6658
  await provider.ensureReferenceData?.();
6646
6659
  onboarding.complete();
6647
6660
  }, [provider, onboarding.complete]);
@@ -6704,7 +6717,7 @@ function InventoryPage({ config: appConfig, provider, store, registries }) {
6704
6717
  { id: "products", render: () => /* @__PURE__ */ jsx(ProductListView, { onNew: () => navigate("products-new"), onOpen: (id) => navigate(`products-detail:${id}`) }) },
6705
6718
  { id: "products-list", render: () => /* @__PURE__ */ jsx(ProductListView, { onNew: () => navigate("products-new"), onOpen: (id) => navigate(`products-detail:${id}`) }) },
6706
6719
  { id: "products-new", render: () => /* @__PURE__ */ jsx(ProductCrudForm, { onSaved: () => navigate("products-list") }) },
6707
- { id: "products-edit", render: ({ id }) => /* @__PURE__ */ jsx(ProductCrudForm, { editId: id, onSaved: () => navigate(`products-detail:${id}`) }) },
6720
+ { id: "products-edit", render: ({ id }) => /* @__PURE__ */ jsx(ProductCrudForm, { editId: id, onSaved: () => navigate(`products-detail:${id}`), onOpenTab: (tab) => navigate(`products-${tab}:${id}`) }) },
6708
6721
  { id: "products-detail", render: ({ id }) => /* @__PURE__ */ jsx(ProductDetailView, { productId: id, onBack: () => navigate("products-list"), onEdit: () => navigate(`products-edit:${id}`) }) },
6709
6722
  // Every tab writes `/products/<id>/<tab>` into the URL, so each of those
6710
6723
  // links has to come back to the same page with that tab open. Only
@@ -9972,6 +9985,9 @@ var supplierEntity = {
9972
9985
  // office that invoices, the warehouse the goods leave from). `layout:
9973
9986
  // 'person'` gives the record an "Addresses" tab backed by public.addresses,
9974
9987
  // which is the same relation clients and patients already use.
9988
+ // Declares the supplier as someone the house pays, which is what keeps
9989
+ // the "Bank accounts" section on the record.
9990
+ { key: "payeeAccount", label: "Bank account", type: "bank", showInTable: false, showInDetail: false },
9975
9991
  { key: "notes", label: "Notes", type: "textarea" },
9976
9992
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
9977
9993
  ],
@@ -21466,7 +21482,7 @@ function createInventoryPlugin(options) {
21466
21482
  const provider = options?.dataProvider ?? createInventoryDataProvider();
21467
21483
  const store = createInventoryStore(provider);
21468
21484
  const dashboardWidgets = createInventoryDashboardWidgets({ config, provider, store });
21469
- const PageComponent = () => React6.createElement(InventoryPage, { config, provider, store, registries: inventoryRegistries });
21485
+ const PageComponent = () => React14.createElement(InventoryPage, { config, provider, store, registries: inventoryRegistries });
21470
21486
  return {
21471
21487
  id: "inventory",
21472
21488
  // Como esta conta refaz o módulo com as opções DELA. Ver PluginRebuild:
@@ -21635,9 +21651,9 @@ function createInventoryPlugin(options) {
21635
21651
  // Categories, Units and Suppliers all existed in code and appeared
21636
21652
  // nowhere. financial and crm already render through it.
21637
21653
  component: (() => {
21638
- const Tab = () => React6.createElement(PluginSettingsPanel, {
21654
+ const Tab = () => React14.createElement(PluginSettingsPanel, {
21639
21655
  title: config.labels.pageTitle,
21640
- generalSettings: React6.createElement(InventoryGeneralSettings, { config }),
21656
+ generalSettings: React14.createElement(InventoryGeneralSettings, { config }),
21641
21657
  registries: inventoryRegistries,
21642
21658
  hostPluginId: "inventory",
21643
21659
  routeBase: "/settings/inventory"