Skip to main content

Product field access

This page lists every field of the product form with the rules that make it read-only or required, and the exact rule that computes them. The rule is resolveProductAccess in apps/web/utils/products/product-access.ts. The Nuxt client and the Nitro server use the same rule.

Field matrix​

Legend:

  • Needs edit: read-only on an existing product without org:products:edit.
  • Catalog lock: read-only on an existing product when catalog mode is ON and the organization is not PARTNER.
  • Vendor lock: read-only on an existing product when the organization is VENDOR and hasBeenStocked is true.
  • Required in catalog: required when catalog mode is ON and the product is not a KIT.
  • Affects name: part of the catalog name formula.
Field keyLabelSectionProduct typeNeeds editCatalog lockVendor lockRequired in catalogAffects name
nameNombre del ProductoInformación Generalallyesnoyesno (generated for STOCK)—
skuSKUInformación Generalallyesnonono (always required)no
brandMarcaInformación Generalallyesnoyesnono
familiaFamilia de productoInformación GeneralKITyesnoyesnono
costCostoInformación Generalallyesnononono
supplierProveedorInformación GeneralSTOCKyesnononono
tipoTipo de ProductoInformación GeneralSTOCKyesnoyesyesyes
grupoGrupoInformación GeneralSTOCKyesnoyesnono
tagsEtiquetasInformación Generalallyesnononono
saborSaborDescripciónSTOCKyesnononoyes
colorColorDescripciónSTOCKyesnononoyes
tallaTalla o MedidaDescripciónSTOCKyesnononoyes
presentacionPresentaciónDetalles del productoSTOCKyesyesyesyesyes
contenidoContenido de la presentaciónDetalles del productoSTOCKyesyesyesyes (≥ 1)yes
unidadUnidad de ventaDetalles del productoSTOCKyesyesyesyesyes
modeloModeloDetalles del productoSTOCKyesyesyesyesyes
piecesPerBoxPiezas por empaque maestroDetalles del productoSTOCKyesyesyesnono
piecesPerPalletPiezas por palletDetalles del productoSTOCKyesyesyesnono
usesBatchUsa LotesDetalles del productoSTOCKyesyesyesnono
usesExpirationUsa CaducidadesDetalles del productoSTOCKyesyesyesnono
usesSerialUsa SerialesDetalles del productoSTOCKyesyesyesnono
dimensionsLargo, Alto, Ancho, PesoDimensionesSTOCKyesyesyesnono

Barcodes are not part of this matrix. See Barcodes.

Field lists in code​

ConstantFileMembers
CATALOG_REQUIRED_FIELDSapps/web/utils/products/product-access.tspresentacion, contenido, unidad, tipo, modelo
NAME_FIELDSapps/web/utils/products/product-access.tsCATALOG_REQUIRED_FIELDS + color, talla, sabor
DETAILS_FIELDSapps/web/utils/products/product-access.tspresentacion, contenido, unidad, modelo, piecesPerBox, piecesPerPallet, usesBatch, usesExpiration, usesSerial, dimensions
VENDOR_LOCKED_FIELDSapps/web/utils/products/product-access.tsname, brand, familia, grupo, tipo, modelo, presentacion, contenido, unidad, piecesPerBox, piecesPerPallet, usesBatch, usesSerial, usesExpiration, dimensions
PRODUCT_LOGISTICS_FIELDSapps/web/utils/products/logistics.tspresentation, content, unit, model, piecesPerBox, piecesPerPallet, usesBatch, usesExpiration, usesSerial, dimensions
CATALOG_REQUIRED_FIELDS (server)modules/inventory/src/products/domain/services/CatalogNameFields.tspresentation, content, unit, categoryId, model
NAME_FIELDS (server)modules/inventory/src/products/domain/services/CatalogNameFields.tsserver CATALOG_REQUIRED_FIELDS + color, size, flavor

Form key to PATCH key​

Built by buildProductUpdateDto in apps/web/utils/products/update-product-dto.ts.

Form keyPATCH key
presentacionpresentation
contenidocontent
unidadunit
modelomodel
tipo (selected category id)categoryId
tallasize
saborflavor
colorcolor
groupgroup

The rule​

Inputs​

ProductAccessInput:

InputSource in the client (apps/web/composables/products/useProductAccess.ts)
isCreatePage option (true in new.vue and import-products.vue)
canEditorg:products:edit
isCatalogModeorganization.settings.CATALOG_MODE === true, or the dev override
orgTypeorganization.type (PARTNER or VENDOR)
hasBeenStockedproduct.hasBeenStocked (default false)
isStockproduct type is not KIT

Read-only​

For every field:

readonly[field] =
!isCreate && (
!canEdit
|| (field in DETAILS_FIELDS && !logisticsAllowed)
|| (field in VENDOR_LOCKED_FIELDS && vendorLocked)
)

logisticsAllowed = isCreate || (canEdit && (!isCatalogMode || orgType === 'PARTNER'))
vendorLocked = orgType === 'VENDOR' && hasBeenStocked

Other outputs​

OutputValue
canEditLogisticslogisticsAllowed
requiredFieldsCATALOG_REQUIRED_FIELDS when isCatalogMode && isStock, otherwise []
importDimensionsfalse when isCatalogMode && orgType === 'VENDOR', otherwise true
canViewCatalogTabisCatalogMode (shows the Detalle de catálogo tab in the product list)

Create mode​

AspectBehavior
Read-only fieldsNone. Every field is editable.
Required fieldsrequiredFields applies (catalog ON + STOCK).
Name (catalog ON + STOCK)Read-only preview generated from the form. Placeholder until all five required fields are filled: Completa los datos del producto para generar el nombre...
Dimensions on importDropped from rows and from the grid when importDimensions is false.

Edit mode​

AspectBehavior
Name (catalog ON + STOCK)Read-only. Shows the stored name until the server saves a new one.
Required fieldsValidated only when a name field changed (changedNameFields).
Missing required field that is read-onlyToast Faltan campos que solo un partner puede completar: <labels>; save is blocked.
Missing required field that is editableToast Completa los campos requeridos: <labels>; save is blocked.
Logistics keys in PATCHOmitted when canEditLogistics is false.
Name in PATCH (catalog ON + STOCK)Omitted.

changedNameFields treats '', null, and undefined as equal, trims strings, and compares contenido numerically. tipo is compared by category id.

Server PATCH guard keys​

PATCH /api/products/:id runs requireLogisticsEdit when the body has any key of PRODUCT_LOGISTICS_FIELDS, including keys with null or false values. categoryId, color, size, and flavor are not guard keys.

Server enforcement summary​

RuleClientServer
org:products:edityesyes (PATCH /api/products/:id)
Catalog lock (logistics fields)yesyes (requireLogisticsEdit)
Vendor lock (hasBeenStocked)yesno
Required catalog fieldsyesyes (MissingCatalogFieldsError, 422)

Barcodes​

RuleValue
Create modeFree (created with org:products:create after the product is created).
Existing product, UIEach action needs its org:barcodes:* permission and canEditLogistics({ canEdit: true, isCatalogMode, orgType }).
Existing product, serverSame rule via requireLogisticsEdit. POST /api/products/:id/barcodes skips it when the caller has org:products:create.
Vendor lockNot applied.

Catalog mode source​

OrganizationEffective CATALOG_MODE
PARTNERIts own settings.CATALOG_MODE === true
VENDOR with a partnertrue when the partner has it true; otherwise its own value
VENDOR without a partnerIts own value

Dev builds only (import.meta.dev): localStorage['feature-flag-catalog-products'] === 'true' forces catalog mode ON in the client. The server ignores it.