@open-mercato/core 0.4.5-develop-3ce83a8b24 → 0.4.5-develop-4849712ccb
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/generated/entities/catalog_product/index.js +16 -0
- package/dist/generated/entities/catalog_product/index.js.map +2 -2
- package/dist/generated/entities/catalog_product_unit_conversion/index.js +27 -0
- package/dist/generated/entities/catalog_product_unit_conversion/index.js.map +7 -0
- package/dist/generated/entities/sales_credit_memo_line/index.js +7 -1
- package/dist/generated/entities/sales_credit_memo_line/index.js.map +2 -2
- package/dist/generated/entities/sales_invoice_line/index.js +7 -1
- package/dist/generated/entities/sales_invoice_line/index.js.map +2 -2
- package/dist/generated/entities/sales_order_line/index.js +6 -0
- package/dist/generated/entities/sales_order_line/index.js.map +2 -2
- package/dist/generated/entities/sales_quote_line/index.js +6 -0
- package/dist/generated/entities/sales_quote_line/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/catalog/api/prices/route.js +123 -8
- package/dist/modules/catalog/api/prices/route.js.map +2 -2
- package/dist/modules/catalog/api/product-unit-conversions/route.js +194 -0
- package/dist/modules/catalog/api/product-unit-conversions/route.js.map +7 -0
- package/dist/modules/catalog/api/products/route.js +351 -201
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +1267 -497
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +733 -210
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/index.js +1 -0
- package/dist/modules/catalog/commands/index.js.map +2 -2
- package/dist/modules/catalog/commands/productUnitConversions.js +503 -0
- package/dist/modules/catalog/commands/productUnitConversions.js.map +7 -0
- package/dist/modules/catalog/commands/products.js +355 -73
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +18 -4
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductUomSection.js +591 -0
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +7 -0
- package/dist/modules/catalog/components/products/productForm.js +66 -5
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/productFormUtils.js +68 -0
- package/dist/modules/catalog/components/products/productFormUtils.js.map +7 -0
- package/dist/modules/catalog/data/entities.js +86 -0
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +65 -3
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/events.js +3 -0
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/lib/unitCodes.js +7 -0
- package/dist/modules/catalog/lib/unitCodes.js.map +7 -0
- package/dist/modules/catalog/lib/unitResolution.js +53 -0
- package/dist/modules/catalog/lib/unitResolution.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260218225422.js +19 -0
- package/dist/modules/catalog/migrations/Migration20260218225422.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260219084500.js +27 -0
- package/dist/modules/catalog/migrations/Migration20260219084500.js.map +7 -0
- package/dist/modules/catalog/search.js +69 -1
- package/dist/modules/catalog/search.js.map +2 -2
- package/dist/modules/catalog/seed/examples.js +91 -42
- package/dist/modules/catalog/seed/examples.js.map +2 -2
- package/dist/modules/dashboards/seed/analytics.js +3 -0
- package/dist/modules/dashboards/seed/analytics.js.map +2 -2
- package/dist/modules/sales/api/order-lines/route.js +98 -15
- package/dist/modules/sales/api/order-lines/route.js.map +2 -2
- package/dist/modules/sales/api/quote-lines/route.js +101 -14
- package/dist/modules/sales/api/quote-lines/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/public/[token]/route.js +87 -12
- package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +1424 -260
- package/dist/modules/sales/commands/documents.js.map +3 -3
- package/dist/modules/sales/commands/shared.js +6 -2
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +216 -86
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +913 -241
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +3 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js +15 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/data/entities.js +59 -3
- package/dist/modules/sales/data/entities.js.map +2 -2
- package/dist/modules/sales/data/validators.js +35 -0
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js +15 -1
- package/dist/modules/sales/frontend/quote/[token]/page.js.map +2 -2
- package/dist/modules/sales/migrations/Migration20260218225423.js +31 -0
- package/dist/modules/sales/migrations/Migration20260218225423.js.map +7 -0
- package/dist/modules/sales/migrations/Migration20260219084501.js +71 -0
- package/dist/modules/sales/migrations/Migration20260219084501.js.map +7 -0
- package/dist/modules/sales/search.js +28 -0
- package/dist/modules/sales/search.js.map +2 -2
- package/dist/modules/sales/seed/examples.js +14 -1
- package/dist/modules/sales/seed/examples.js.map +2 -2
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js +1 -1
- package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
- package/generated/entities/catalog_product/index.ts +8 -0
- package/generated/entities/catalog_product_unit_conversion/index.ts +12 -0
- package/generated/entities/sales_credit_memo_line/index.ts +3 -0
- package/generated/entities/sales_invoice_line/index.ts +3 -0
- package/generated/entities/sales_order_line/index.ts +3 -0
- package/generated/entities/sales_quote_line/index.ts +3 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +2 -2
- package/src/modules/auth/i18n/de.json +1 -1
- package/src/modules/auth/i18n/en.json +1 -1
- package/src/modules/auth/i18n/es.json +1 -1
- package/src/modules/auth/i18n/pl.json +1 -1
- package/src/modules/catalog/api/prices/route.ts +213 -81
- package/src/modules/catalog/api/product-unit-conversions/route.ts +195 -0
- package/src/modules/catalog/api/products/route.ts +638 -402
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2085 -1072
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +1288 -593
- package/src/modules/catalog/commands/index.ts +1 -0
- package/src/modules/catalog/commands/productUnitConversions.ts +626 -0
- package/src/modules/catalog/commands/products.ts +1151 -693
- package/src/modules/catalog/commands/shared.ts +19 -5
- package/src/modules/catalog/components/products/ProductUomSection.tsx +745 -0
- package/src/modules/catalog/components/products/productForm.ts +369 -256
- package/src/modules/catalog/components/products/productFormUtils.ts +82 -0
- package/src/modules/catalog/data/entities.ts +82 -1
- package/src/modules/catalog/data/validators.ts +118 -34
- package/src/modules/catalog/events.ts +3 -0
- package/src/modules/catalog/i18n/de.json +56 -0
- package/src/modules/catalog/i18n/en.json +56 -0
- package/src/modules/catalog/i18n/es.json +56 -0
- package/src/modules/catalog/i18n/pl.json +56 -0
- package/src/modules/catalog/lib/unitCodes.ts +1 -0
- package/src/modules/catalog/lib/unitResolution.ts +62 -0
- package/src/modules/catalog/migrations/.snapshot-open-mercato.json +245 -0
- package/src/modules/catalog/migrations/Migration20260218225422.ts +21 -0
- package/src/modules/catalog/migrations/Migration20260219084500.ts +26 -0
- package/src/modules/catalog/search.ts +73 -1
- package/src/modules/catalog/seed/examples.ts +552 -479
- package/src/modules/dashboards/i18n/de.json +1 -1
- package/src/modules/dashboards/i18n/en.json +1 -1
- package/src/modules/dashboards/i18n/es.json +1 -1
- package/src/modules/dashboards/i18n/pl.json +1 -1
- package/src/modules/dashboards/seed/analytics.ts +3 -0
- package/src/modules/sales/api/order-lines/route.ts +158 -68
- package/src/modules/sales/api/quote-lines/route.ts +161 -67
- package/src/modules/sales/api/quotes/public/[token]/route.ts +122 -36
- package/src/modules/sales/commands/documents.ts +4250 -2424
- package/src/modules/sales/commands/shared.ts +7 -2
- package/src/modules/sales/components/documents/ItemsSection.tsx +580 -310
- package/src/modules/sales/components/documents/LineItemDialog.tsx +1988 -833
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +17 -3
- package/src/modules/sales/components/documents/lineItemTypes.ts +6 -0
- package/src/modules/sales/data/entities.ts +53 -0
- package/src/modules/sales/data/validators.ts +36 -0
- package/src/modules/sales/frontend/quote/[token]/page.tsx +25 -1
- package/src/modules/sales/i18n/de.json +23 -3
- package/src/modules/sales/i18n/en.json +23 -3
- package/src/modules/sales/i18n/es.json +23 -3
- package/src/modules/sales/i18n/pl.json +23 -3
- package/src/modules/sales/lib/types.ts +30 -0
- package/src/modules/sales/migrations/.snapshot-open-mercato.json +172 -0
- package/src/modules/sales/migrations/Migration20260218225423.ts +37 -0
- package/src/modules/sales/migrations/Migration20260219084501.ts +73 -0
- package/src/modules/sales/search.ts +28 -0
- package/src/modules/sales/seed/examples.ts +20 -1
- package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +1 -1
- package/src/modules/workflows/i18n/de.json +4 -4
- package/src/modules/workflows/i18n/en.json +4 -4
- package/src/modules/workflows/i18n/es.json +4 -4
- package/src/modules/workflows/i18n/pl.json +4 -4
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { REFERENCE_UNIT_CODES, type ReferenceUnitCode } from "@open-mercato/shared/lib/units/unitCodes";
|
|
2
|
+
import { canonicalizeUnitCode } from "../../lib/unitCodes";
|
|
3
|
+
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
4
|
+
import type { ProductUnitConversionDraft } from "./productForm";
|
|
5
|
+
|
|
6
|
+
export const UNIT_PRICE_REFERENCE_UNITS = new Set<ReferenceUnitCode>(REFERENCE_UNIT_CODES);
|
|
7
|
+
|
|
8
|
+
export function toTrimmedOrNull(value: unknown): string | null {
|
|
9
|
+
if (typeof value !== "string") return null;
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
return trimmed.length ? trimmed : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseNumericInput(value: unknown): number {
|
|
15
|
+
if (typeof value === "number") return value;
|
|
16
|
+
if (typeof value === "string") {
|
|
17
|
+
const normalized = value.trim().replace(/\s+/g, "").replace(/,/g, ".");
|
|
18
|
+
if (!normalized.length) return Number.NaN;
|
|
19
|
+
return Number(normalized);
|
|
20
|
+
}
|
|
21
|
+
return Number(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function toPositiveNumberOrNull(value: unknown): number | null {
|
|
25
|
+
const numeric = parseNumericInput(value);
|
|
26
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return null;
|
|
27
|
+
return numeric;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function toIntegerInRangeOrDefault(
|
|
31
|
+
value: unknown,
|
|
32
|
+
min: number,
|
|
33
|
+
max: number,
|
|
34
|
+
fallback: number,
|
|
35
|
+
): number {
|
|
36
|
+
const numeric = parseNumericInput(value);
|
|
37
|
+
if (!Number.isInteger(numeric) || numeric < min || numeric > max)
|
|
38
|
+
return fallback;
|
|
39
|
+
return numeric;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type ProductUnitConversionInput = {
|
|
43
|
+
id?: string | null;
|
|
44
|
+
unitCode: string;
|
|
45
|
+
toBaseFactor: number;
|
|
46
|
+
sortOrder: number;
|
|
47
|
+
isActive: boolean;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function normalizeProductConversionInputs(
|
|
51
|
+
rows: ProductUnitConversionDraft[] | undefined,
|
|
52
|
+
duplicateMessage: string,
|
|
53
|
+
): ProductUnitConversionInput[] {
|
|
54
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
55
|
+
const normalized: ProductUnitConversionInput[] = [];
|
|
56
|
+
const seen = new Set<string>();
|
|
57
|
+
for (const row of list) {
|
|
58
|
+
const unitCode = canonicalizeUnitCode(row?.unitCode);
|
|
59
|
+
const toBaseFactor = toPositiveNumberOrNull(row?.toBaseFactor);
|
|
60
|
+
if (!unitCode || toBaseFactor === null) continue;
|
|
61
|
+
const unitKey = unitCode.toLowerCase();
|
|
62
|
+
if (seen.has(unitKey)) {
|
|
63
|
+
throw createCrudFormError(duplicateMessage, {
|
|
64
|
+
unitConversions: duplicateMessage,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
seen.add(unitKey);
|
|
68
|
+
normalized.push({
|
|
69
|
+
id: toTrimmedOrNull(row?.id),
|
|
70
|
+
unitCode,
|
|
71
|
+
toBaseFactor,
|
|
72
|
+
sortOrder: toIntegerInRangeOrDefault(
|
|
73
|
+
row?.sortOrder,
|
|
74
|
+
0,
|
|
75
|
+
100000,
|
|
76
|
+
normalized.length * 10,
|
|
77
|
+
),
|
|
78
|
+
isActive: row?.isActive !== false,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return normalized;
|
|
82
|
+
}
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
CatalogProductRelationType,
|
|
16
16
|
CatalogProductType,
|
|
17
17
|
} from './types'
|
|
18
|
+
import type { ReferenceUnitCode } from '@open-mercato/shared/lib/units/unitCodes'
|
|
18
19
|
|
|
19
20
|
@Entity({ tableName: 'catalog_product_option_schemas' })
|
|
20
21
|
@Index({
|
|
@@ -70,7 +71,14 @@ export class CatalogOptionSchemaTemplate {
|
|
|
70
71
|
@Unique({ name: 'catalog_products_sku_scope_unique', properties: ['organizationId', 'tenantId', 'sku'] })
|
|
71
72
|
@Unique({ name: 'catalog_products_handle_scope_unique', properties: ['organizationId', 'tenantId', 'handle'] })
|
|
72
73
|
export class CatalogProduct {
|
|
73
|
-
[OptionalProps]?:
|
|
74
|
+
[OptionalProps]?:
|
|
75
|
+
| 'createdAt'
|
|
76
|
+
| 'updatedAt'
|
|
77
|
+
| 'deletedAt'
|
|
78
|
+
| 'defaultSalesUnitQuantity'
|
|
79
|
+
| 'uomRoundingScale'
|
|
80
|
+
| 'uomRoundingMode'
|
|
81
|
+
| 'unitPriceEnabled'
|
|
74
82
|
|
|
75
83
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
76
84
|
id!: string
|
|
@@ -114,6 +122,27 @@ export class CatalogProduct {
|
|
|
114
122
|
@Property({ name: 'default_unit', type: 'text', nullable: true })
|
|
115
123
|
defaultUnit?: string | null
|
|
116
124
|
|
|
125
|
+
@Property({ name: 'default_sales_unit', type: 'text', nullable: true })
|
|
126
|
+
defaultSalesUnit?: string | null
|
|
127
|
+
|
|
128
|
+
@Property({ name: 'default_sales_unit_quantity', type: 'numeric', precision: 18, scale: 6, default: '1' })
|
|
129
|
+
defaultSalesUnitQuantity: string = '1'
|
|
130
|
+
|
|
131
|
+
@Property({ name: 'uom_rounding_scale', type: 'smallint', default: 4 })
|
|
132
|
+
uomRoundingScale: number = 4
|
|
133
|
+
|
|
134
|
+
@Property({ name: 'uom_rounding_mode', type: 'text', default: 'half_up' })
|
|
135
|
+
uomRoundingMode: 'half_up' | 'down' | 'up' = 'half_up'
|
|
136
|
+
|
|
137
|
+
@Property({ name: 'unit_price_enabled', type: 'boolean', default: false })
|
|
138
|
+
unitPriceEnabled: boolean = false
|
|
139
|
+
|
|
140
|
+
@Property({ name: 'unit_price_reference_unit', type: 'text', nullable: true })
|
|
141
|
+
unitPriceReferenceUnit?: ReferenceUnitCode | null
|
|
142
|
+
|
|
143
|
+
@Property({ name: 'unit_price_base_quantity', type: 'numeric', precision: 18, scale: 6, nullable: true })
|
|
144
|
+
unitPriceBaseQuantity?: string | null
|
|
145
|
+
|
|
117
146
|
@Property({ name: 'default_media_id', type: 'uuid', nullable: true })
|
|
118
147
|
defaultMediaId?: string | null
|
|
119
148
|
|
|
@@ -174,7 +203,59 @@ export class CatalogProduct {
|
|
|
174
203
|
@OneToMany(() => CatalogProductTagAssignment, (assignment) => assignment.product)
|
|
175
204
|
tagAssignments = new Collection<CatalogProductTagAssignment>(this)
|
|
176
205
|
|
|
206
|
+
@OneToMany(() => CatalogProductUnitConversion, (conversion) => conversion.product)
|
|
207
|
+
unitConversions = new Collection<CatalogProductUnitConversion>(this)
|
|
177
208
|
}
|
|
209
|
+
|
|
210
|
+
@Entity({ tableName: 'catalog_product_unit_conversions' })
|
|
211
|
+
@Index({
|
|
212
|
+
name: 'catalog_product_unit_conversions_scope_idx',
|
|
213
|
+
properties: ['organizationId', 'tenantId', 'product'],
|
|
214
|
+
})
|
|
215
|
+
@Unique({
|
|
216
|
+
name: 'catalog_product_unit_conversions_unique',
|
|
217
|
+
properties: ['product', 'unitCode'],
|
|
218
|
+
})
|
|
219
|
+
export class CatalogProductUnitConversion {
|
|
220
|
+
[OptionalProps]?: 'createdAt' | 'updatedAt' | 'deletedAt' | 'sortOrder' | 'isActive'
|
|
221
|
+
|
|
222
|
+
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
223
|
+
id!: string
|
|
224
|
+
|
|
225
|
+
@ManyToOne(() => CatalogProduct, { fieldName: 'product_id', deleteRule: 'cascade' })
|
|
226
|
+
product!: CatalogProduct
|
|
227
|
+
|
|
228
|
+
@Property({ name: 'organization_id', type: 'uuid' })
|
|
229
|
+
organizationId!: string
|
|
230
|
+
|
|
231
|
+
@Property({ name: 'tenant_id', type: 'uuid' })
|
|
232
|
+
tenantId!: string
|
|
233
|
+
|
|
234
|
+
@Property({ name: 'unit_code', type: 'text' })
|
|
235
|
+
unitCode!: string
|
|
236
|
+
|
|
237
|
+
@Property({ name: 'to_base_factor', type: 'numeric', precision: 24, scale: 12 })
|
|
238
|
+
toBaseFactor!: string
|
|
239
|
+
|
|
240
|
+
@Property({ name: 'sort_order', type: 'integer', default: 0 })
|
|
241
|
+
sortOrder: number = 0
|
|
242
|
+
|
|
243
|
+
@Property({ name: 'is_active', type: 'boolean', default: true })
|
|
244
|
+
isActive: boolean = true
|
|
245
|
+
|
|
246
|
+
@Property({ name: 'metadata', type: 'jsonb', nullable: true })
|
|
247
|
+
metadata?: Record<string, unknown> | null
|
|
248
|
+
|
|
249
|
+
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
250
|
+
createdAt: Date = new Date()
|
|
251
|
+
|
|
252
|
+
@Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
|
|
253
|
+
updatedAt: Date = new Date()
|
|
254
|
+
|
|
255
|
+
@Property({ name: 'deleted_at', type: Date, nullable: true })
|
|
256
|
+
deletedAt?: Date | null
|
|
257
|
+
}
|
|
258
|
+
|
|
178
259
|
@Entity({ tableName: 'catalog_product_categories' })
|
|
179
260
|
@Index({ name: 'catalog_product_categories_scope_idx', properties: ['organizationId', 'tenantId'] })
|
|
180
261
|
@Unique({ name: 'catalog_product_categories_slug_unique', properties: ['organizationId', 'tenantId', 'slug'] })
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { CATALOG_PRICE_DISPLAY_MODES, CATALOG_PRODUCT_TYPES } from './types'
|
|
3
|
+
import { REFERENCE_UNIT_CODES } from '../lib/unitCodes'
|
|
3
4
|
|
|
4
5
|
const uuid = () => z.string().uuid()
|
|
5
6
|
|
|
@@ -107,42 +108,102 @@ export const offerUpdateSchema = z
|
|
|
107
108
|
)
|
|
108
109
|
|
|
109
110
|
const productTypeSchema = z.enum(CATALOG_PRODUCT_TYPES)
|
|
111
|
+
const uomRoundingModeSchema = z.enum(['half_up', 'down', 'up'])
|
|
112
|
+
const unitPriceReferenceUnitSchema = z.enum(REFERENCE_UNIT_CODES)
|
|
113
|
+
const unitPriceConfigSchema = z.object({
|
|
114
|
+
enabled: z.boolean().optional(),
|
|
115
|
+
referenceUnit: unitPriceReferenceUnitSchema.nullable().optional(),
|
|
116
|
+
baseQuantity: z.coerce.number().positive().optional(),
|
|
117
|
+
})
|
|
110
118
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
defaultUnit
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
height: z.coerce.number().min(0).optional(),
|
|
131
|
-
depth: z.coerce.number().min(0).optional(),
|
|
132
|
-
unit: z.string().trim().max(25).optional(),
|
|
119
|
+
function productUomCrossFieldRefinement(
|
|
120
|
+
input: {
|
|
121
|
+
defaultUnit?: string | null
|
|
122
|
+
defaultSalesUnit?: string | null
|
|
123
|
+
unitPriceEnabled?: boolean
|
|
124
|
+
unitPriceReferenceUnit?: string | null
|
|
125
|
+
unitPriceBaseQuantity?: number
|
|
126
|
+
unitPrice?: { enabled?: boolean; referenceUnit?: string | null; baseQuantity?: number }
|
|
127
|
+
},
|
|
128
|
+
ctx: z.RefinementCtx,
|
|
129
|
+
) {
|
|
130
|
+
const defaultUnit = typeof input.defaultUnit === 'string' ? input.defaultUnit.trim() : ''
|
|
131
|
+
const defaultSalesUnit =
|
|
132
|
+
typeof input.defaultSalesUnit === 'string' ? input.defaultSalesUnit.trim() : ''
|
|
133
|
+
if (defaultSalesUnit && !defaultUnit) {
|
|
134
|
+
ctx.addIssue({
|
|
135
|
+
code: z.ZodIssueCode.custom,
|
|
136
|
+
path: ['defaultSalesUnit'],
|
|
137
|
+
message: 'catalog.products.validation.baseUnitRequired',
|
|
133
138
|
})
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
}
|
|
140
|
+
const unitPriceEnabled = input.unitPrice?.enabled ?? input.unitPriceEnabled ?? false
|
|
141
|
+
if (!unitPriceEnabled) return
|
|
142
|
+
const referenceUnit =
|
|
143
|
+
input.unitPrice?.referenceUnit ?? input.unitPriceReferenceUnit ?? null
|
|
144
|
+
const baseQuantity =
|
|
145
|
+
input.unitPrice?.baseQuantity ?? input.unitPriceBaseQuantity ?? null
|
|
146
|
+
if (!referenceUnit) {
|
|
147
|
+
ctx.addIssue({
|
|
148
|
+
code: z.ZodIssueCode.custom,
|
|
149
|
+
path: ['unitPrice'],
|
|
150
|
+
message: 'catalog.products.validation.referenceUnitRequired',
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
if (baseQuantity === null || baseQuantity === undefined || Number(baseQuantity) <= 0) {
|
|
154
|
+
ctx.addIssue({
|
|
155
|
+
code: z.ZodIssueCode.custom,
|
|
156
|
+
path: ['unitPrice'],
|
|
157
|
+
message: 'catalog.products.unitPrice.errors.baseQuantity',
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const productCreateSchema = scoped
|
|
163
|
+
.extend({
|
|
164
|
+
title: z.string().trim().min(1).max(255),
|
|
165
|
+
subtitle: z.string().trim().max(255).optional(),
|
|
166
|
+
description: z.string().trim().max(4000).optional(),
|
|
167
|
+
sku: skuSchema.optional(),
|
|
168
|
+
handle: handleSchema.optional(),
|
|
169
|
+
taxRateId: uuid().nullable().optional(),
|
|
170
|
+
taxRate: z.coerce.number().min(0).max(100).optional().nullable(),
|
|
171
|
+
productType: productTypeSchema.default('simple'),
|
|
172
|
+
statusEntryId: uuid().optional(),
|
|
173
|
+
primaryCurrencyCode: currencyCodeSchema.optional(),
|
|
174
|
+
defaultUnit: z.string().trim().max(50).optional().nullable(),
|
|
175
|
+
defaultSalesUnit: z.string().trim().max(50).optional().nullable(),
|
|
176
|
+
defaultSalesUnitQuantity: z.coerce.number().positive().optional(),
|
|
177
|
+
uomRoundingScale: z.coerce.number().int().min(0).max(6).optional(),
|
|
178
|
+
uomRoundingMode: uomRoundingModeSchema.optional(),
|
|
179
|
+
unitPriceEnabled: z.boolean().optional(),
|
|
180
|
+
unitPriceReferenceUnit: unitPriceReferenceUnitSchema.nullable().optional(),
|
|
181
|
+
unitPriceBaseQuantity: z.coerce.number().positive().optional(),
|
|
182
|
+
unitPrice: unitPriceConfigSchema.optional(),
|
|
183
|
+
defaultMediaId: uuid().optional().nullable(),
|
|
184
|
+
defaultMediaUrl: z.string().trim().max(500).optional().nullable(),
|
|
185
|
+
weightValue: z.coerce.number().min(0).optional().nullable(),
|
|
186
|
+
weightUnit: z.string().trim().max(25).optional().nullable(),
|
|
187
|
+
dimensions: z
|
|
188
|
+
.object({
|
|
189
|
+
width: z.coerce.number().min(0).optional(),
|
|
190
|
+
height: z.coerce.number().min(0).optional(),
|
|
191
|
+
depth: z.coerce.number().min(0).optional(),
|
|
192
|
+
unit: z.string().trim().max(25).optional(),
|
|
193
|
+
})
|
|
194
|
+
.optional()
|
|
195
|
+
.nullable(),
|
|
196
|
+
optionSchemaId: uuid().nullable().optional(),
|
|
197
|
+
optionSchema: optionSchema.optional(),
|
|
198
|
+
customFieldsetCode: slugSchema.nullable().optional(),
|
|
199
|
+
isConfigurable: z.boolean().optional(),
|
|
200
|
+
isActive: z.boolean().optional(),
|
|
201
|
+
metadata: metadataSchema,
|
|
202
|
+
offers: z.array(offerInputSchema.omit({ id: true })).optional(),
|
|
203
|
+
categoryIds: z.array(uuid()).max(100).optional(),
|
|
204
|
+
tags: z.array(tagLabelSchema).max(100).optional(),
|
|
205
|
+
})
|
|
206
|
+
.superRefine(productUomCrossFieldRefinement)
|
|
146
207
|
|
|
147
208
|
export const productUpdateSchema = z
|
|
148
209
|
.object({
|
|
@@ -152,6 +213,7 @@ export const productUpdateSchema = z
|
|
|
152
213
|
.extend({
|
|
153
214
|
productType: productTypeSchema.optional(),
|
|
154
215
|
})
|
|
216
|
+
.superRefine(productUomCrossFieldRefinement)
|
|
155
217
|
|
|
156
218
|
export const variantCreateSchema = scoped.extend({
|
|
157
219
|
productId: uuid(),
|
|
@@ -265,6 +327,25 @@ export const categoryUpdateSchema = z
|
|
|
265
327
|
})
|
|
266
328
|
.merge(categoryCreateSchema.partial())
|
|
267
329
|
|
|
330
|
+
export const productUnitConversionCreateSchema = scoped.extend({
|
|
331
|
+
productId: uuid(),
|
|
332
|
+
unitCode: z.string().trim().min(1).max(50),
|
|
333
|
+
toBaseFactor: z.coerce.number().positive().max(1_000_000),
|
|
334
|
+
sortOrder: z.coerce.number().int().optional(),
|
|
335
|
+
isActive: z.boolean().optional(),
|
|
336
|
+
metadata: metadataSchema,
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
export const productUnitConversionUpdateSchema = z
|
|
340
|
+
.object({
|
|
341
|
+
id: uuid(),
|
|
342
|
+
})
|
|
343
|
+
.merge(productUnitConversionCreateSchema.omit({ productId: true }).partial())
|
|
344
|
+
|
|
345
|
+
export const productUnitConversionDeleteSchema = scoped.extend({
|
|
346
|
+
id: uuid(),
|
|
347
|
+
})
|
|
348
|
+
|
|
268
349
|
export type ProductCreateInput = z.infer<typeof productCreateSchema>
|
|
269
350
|
export type ProductUpdateInput = z.infer<typeof productUpdateSchema>
|
|
270
351
|
export type VariantCreateInput = z.infer<typeof variantCreateSchema>
|
|
@@ -280,3 +361,6 @@ export type CategoryUpdateInput = z.infer<typeof categoryUpdateSchema>
|
|
|
280
361
|
export type OfferInput = z.infer<typeof offerInputSchema>
|
|
281
362
|
export type OfferCreateInput = z.infer<typeof offerCreateSchema>
|
|
282
363
|
export type OfferUpdateInput = z.infer<typeof offerUpdateSchema>
|
|
364
|
+
export type ProductUnitConversionCreateInput = z.infer<typeof productUnitConversionCreateSchema>
|
|
365
|
+
export type ProductUnitConversionUpdateInput = z.infer<typeof productUnitConversionUpdateSchema>
|
|
366
|
+
export type ProductUnitConversionDeleteInput = z.infer<typeof productUnitConversionDeleteSchema>
|
|
@@ -10,6 +10,9 @@ const events = [
|
|
|
10
10
|
{ id: 'catalog.product.created', label: 'Product Created', entity: 'product', category: 'crud' },
|
|
11
11
|
{ id: 'catalog.product.updated', label: 'Product Updated', entity: 'product', category: 'crud' },
|
|
12
12
|
{ id: 'catalog.product.deleted', label: 'Product Deleted', entity: 'product', category: 'crud' },
|
|
13
|
+
{ id: 'catalog.product_unit_conversion.created', label: 'Product Unit Conversion Created', entity: 'product_unit_conversion', category: 'crud' },
|
|
14
|
+
{ id: 'catalog.product_unit_conversion.updated', label: 'Product Unit Conversion Updated', entity: 'product_unit_conversion', category: 'crud' },
|
|
15
|
+
{ id: 'catalog.product_unit_conversion.deleted', label: 'Product Unit Conversion Deleted', entity: 'product_unit_conversion', category: 'crud' },
|
|
13
16
|
|
|
14
17
|
// Categories
|
|
15
18
|
{ id: 'catalog.category.created', label: 'Category Created', entity: 'category', category: 'crud' },
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"catalog.audit.prices.create": "Preis erstellen",
|
|
17
17
|
"catalog.audit.prices.delete": "Preis löschen",
|
|
18
18
|
"catalog.audit.prices.update": "Preis aktualisieren",
|
|
19
|
+
"catalog.audit.productUnitConversions.create": "Produkteinheiten-Umrechnung erstellen",
|
|
20
|
+
"catalog.audit.productUnitConversions.delete": "Produkteinheiten-Umrechnung löschen",
|
|
21
|
+
"catalog.audit.productUnitConversions.update": "Produkteinheiten-Umrechnung aktualisieren",
|
|
19
22
|
"catalog.audit.products.create": "Produkt erstellen",
|
|
20
23
|
"catalog.audit.products.delete": "Produkt löschen",
|
|
21
24
|
"catalog.audit.products.update": "Produkt aktualisieren",
|
|
@@ -394,6 +397,7 @@
|
|
|
394
397
|
"catalog.products.edit.weight.value": "Gewicht",
|
|
395
398
|
"catalog.products.errors.handleExists": "Handle wird bereits verwendet.",
|
|
396
399
|
"catalog.products.errors.skuExists": "SKU wird bereits verwendet.",
|
|
400
|
+
"catalog.products.errors.taxClassNotFound": "Steuerklasse nicht gefunden.",
|
|
397
401
|
"catalog.products.filters.active": "Aktiv",
|
|
398
402
|
"catalog.products.filters.categories": "Kategorien",
|
|
399
403
|
"catalog.products.filters.categoriesLoadError": "Kategorien konnten nicht geladen werden",
|
|
@@ -454,12 +458,64 @@
|
|
|
454
458
|
"catalog.products.types.grouped": "Gruppiert",
|
|
455
459
|
"catalog.products.types.simple": "Einfach",
|
|
456
460
|
"catalog.products.types.virtual": "Virtuell",
|
|
461
|
+
"catalog.products.unitPrice.baseQuantity": "Basismenge für Referenz",
|
|
462
|
+
"catalog.products.unitPrice.enable": "EU-Grundpreisanzeige aktivieren",
|
|
463
|
+
"catalog.products.unitPrice.errors.baseQuantity": "Basismenge ist erforderlich, wenn die Grundpreisanzeige aktiviert ist.",
|
|
464
|
+
"catalog.products.unitPrice.errors.referenceUnit": "Referenzeinheit ist erforderlich, wenn die Grundpreisanzeige aktiviert ist.",
|
|
465
|
+
"catalog.products.unitPrice.hint": "Zeigt den berechneten Preis pro ausgewählter Referenzeinheit. In den meisten Fällen Menge 1 verwenden.",
|
|
466
|
+
"catalog.products.unitPrice.hintWithPreview": "Zeigt den berechneten Preis pro {{quantity}} {{unit}}. Für die meisten Produkte 1 verwenden (z. B. 1 kg, 1 l, 1 m²).",
|
|
467
|
+
"catalog.products.unitPrice.options.kg": "1 kg",
|
|
468
|
+
"catalog.products.unitPrice.options.l": "1 l",
|
|
469
|
+
"catalog.products.unitPrice.options.m2": "1 m²",
|
|
470
|
+
"catalog.products.unitPrice.options.m3": "1 m³",
|
|
471
|
+
"catalog.products.unitPrice.options.pc": "1 Stk.",
|
|
472
|
+
"catalog.products.unitPrice.referenceUnit": "Referenzeinheit",
|
|
473
|
+
"catalog.products.unitPrice.selectReferenceUnit": "Referenzeinheit auswählen",
|
|
474
|
+
"catalog.products.uom.active": "Aktiv",
|
|
475
|
+
"catalog.products.uom.addConversion": "Umrechnung hinzufügen",
|
|
476
|
+
"catalog.products.uom.baseUnit": "Basiseinheit",
|
|
477
|
+
"catalog.products.uom.conversionOrderHint": "Nutze die Pfeile, um die Umrechnungspriorität neu zu ordnen.",
|
|
478
|
+
"catalog.products.uom.conversionPreview": "1 {{fromUnit}} = {{factor}} {{baseUnit}}",
|
|
479
|
+
"catalog.products.uom.conversionUnit": "Verkaufseinheit",
|
|
480
|
+
"catalog.products.uom.conversions": "Produktumrechnungen",
|
|
481
|
+
"catalog.products.uom.defaultSalesQuantity": "Standard-Verkaufsmenge",
|
|
482
|
+
"catalog.products.uom.defaultSalesQuantityHint": "Wird verwendet, um die Menge in Angebots-/Auftragspositionen vorzufüllen. Der Wert wird in der Standard-Verkaufseinheit interpretiert.",
|
|
483
|
+
"catalog.products.uom.defaultSalesQuantityLabel": "Standard-Positionsmenge (in Verkaufseinheit)",
|
|
484
|
+
"catalog.products.uom.defaultSalesQuantityPreview": "Standardposition: {{quantity}} {{salesUnit}}.",
|
|
485
|
+
"catalog.products.uom.defaultSalesQuantityPreviewWithNormalization": "Standardposition: {{quantity}} {{salesUnit}} (= {{normalized}} {{baseUnit}}).",
|
|
486
|
+
"catalog.products.uom.defaultSalesUnit": "Standard-Verkaufseinheit",
|
|
487
|
+
"catalog.products.uom.description": "Basis-/Verkaufseinheiten und Verpackungsumrechnungen festlegen.",
|
|
488
|
+
"catalog.products.uom.emptyConversions": "Noch keine Umrechnungen konfiguriert.",
|
|
489
|
+
"catalog.products.uom.errors.baseRequired": "Basiseinheit ist erforderlich, wenn eine Standard-Verkaufseinheit festgelegt ist.",
|
|
490
|
+
"catalog.products.uom.errors.baseRequiredForConversions": "Basiseinheit ist erforderlich, wenn Umrechnungen konfiguriert sind.",
|
|
491
|
+
"catalog.products.uom.errors.defaultSalesConversionRequired": "Aktive Umrechnung für die Standard-Verkaufseinheit ist erforderlich, wenn sie von der Basiseinheit abweicht.",
|
|
492
|
+
"catalog.products.uom.errors.duplicateConversion": "Doppelte Umrechnungseinheit ist nicht erlaubt.",
|
|
493
|
+
"catalog.products.uom.errors.loadUnits": "Einheiten konnten nicht geladen werden. Bitte versuchen Sie, die Seite zu aktualisieren.",
|
|
494
|
+
"catalog.products.uom.errors.sync": "Produktumrechnungen konnten nicht synchronisiert werden.",
|
|
495
|
+
"catalog.products.uom.loadingUnits": "Einheiten werden geladen...",
|
|
496
|
+
"catalog.products.uom.moveDown": "Umrechnung nach unten verschieben",
|
|
497
|
+
"catalog.products.uom.moveUp": "Umrechnung nach oben verschieben",
|
|
498
|
+
"catalog.products.uom.removeConversion": "Umrechnung entfernen",
|
|
499
|
+
"catalog.products.uom.roundingMode": "Rundungsmodus",
|
|
500
|
+
"catalog.products.uom.roundingModeDown": "Abrunden",
|
|
501
|
+
"catalog.products.uom.roundingModeHalfUp": "Kaufmännisch runden (Standard)",
|
|
502
|
+
"catalog.products.uom.roundingModeUp": "Aufrunden",
|
|
503
|
+
"catalog.products.uom.roundingScale": "Rundungsgenauigkeit (Dezimalstellen)",
|
|
504
|
+
"catalog.products.uom.selectUnit": "Einheit auswählen",
|
|
505
|
+
"catalog.products.uom.sortOrder": "Sortierung",
|
|
506
|
+
"catalog.products.uom.title": "Maßeinheiten",
|
|
507
|
+
"catalog.products.uom.toBaseFactor": "Basisfaktor",
|
|
508
|
+
"catalog.products.validation.baseUnitRequired": "Basiseinheit ist erforderlich, wenn eine Standard-Verkaufseinheit gesetzt ist.",
|
|
509
|
+
"catalog.products.validation.handleFormat": "Handle darf nur Kleinbuchstaben, Ziffern, Bindestriche oder Unterstriche enthalten.",
|
|
510
|
+
"catalog.products.validation.referenceUnitRequired": "Referenzeinheit ist erforderlich, wenn die Grundpreisanzeige aktiviert ist.",
|
|
511
|
+
"catalog.products.validation.titleRequired": "Titel ist erforderlich.",
|
|
457
512
|
"catalog.search.badge.category": "Kategorie",
|
|
458
513
|
"catalog.search.badge.offer": "Kanalangebot",
|
|
459
514
|
"catalog.search.badge.optionSchema": "Optionsschema",
|
|
460
515
|
"catalog.search.badge.priceKind": "Preisart",
|
|
461
516
|
"catalog.search.badge.product": "Produkt",
|
|
462
517
|
"catalog.search.badge.tag": "Schlagwort",
|
|
518
|
+
"catalog.search.badge.unitConversion": "Einheitenumrechnung",
|
|
463
519
|
"catalog.search.badge.variant": "Variante",
|
|
464
520
|
"catalog.search.priceKind.excludingTax": "Exkl. MwSt.",
|
|
465
521
|
"catalog.search.priceKind.includingTax": "Inkl. MwSt.",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"catalog.audit.prices.create": "Create price",
|
|
17
17
|
"catalog.audit.prices.delete": "Delete price",
|
|
18
18
|
"catalog.audit.prices.update": "Update price",
|
|
19
|
+
"catalog.audit.productUnitConversions.create": "Create product unit conversion",
|
|
20
|
+
"catalog.audit.productUnitConversions.delete": "Delete product unit conversion",
|
|
21
|
+
"catalog.audit.productUnitConversions.update": "Update product unit conversion",
|
|
19
22
|
"catalog.audit.products.create": "Create product",
|
|
20
23
|
"catalog.audit.products.delete": "Delete product",
|
|
21
24
|
"catalog.audit.products.update": "Update product",
|
|
@@ -394,6 +397,7 @@
|
|
|
394
397
|
"catalog.products.edit.weight.value": "Weight",
|
|
395
398
|
"catalog.products.errors.handleExists": "Handle already in use.",
|
|
396
399
|
"catalog.products.errors.skuExists": "SKU already in use.",
|
|
400
|
+
"catalog.products.errors.taxClassNotFound": "Tax class not found.",
|
|
397
401
|
"catalog.products.filters.active": "Active",
|
|
398
402
|
"catalog.products.filters.categories": "Categories",
|
|
399
403
|
"catalog.products.filters.categoriesLoadError": "Failed to load categories",
|
|
@@ -454,12 +458,64 @@
|
|
|
454
458
|
"catalog.products.types.grouped": "Grouped",
|
|
455
459
|
"catalog.products.types.simple": "Simple",
|
|
456
460
|
"catalog.products.types.virtual": "Virtual",
|
|
461
|
+
"catalog.products.unitPrice.baseQuantity": "Base quantity for reference",
|
|
462
|
+
"catalog.products.unitPrice.enable": "Enable EU unit price display",
|
|
463
|
+
"catalog.products.unitPrice.errors.baseQuantity": "Base quantity is required when unit price display is enabled.",
|
|
464
|
+
"catalog.products.unitPrice.errors.referenceUnit": "Reference unit is required when unit price display is enabled.",
|
|
465
|
+
"catalog.products.unitPrice.hint": "Show calculated price per selected reference unit. In most cases set quantity to 1.",
|
|
466
|
+
"catalog.products.unitPrice.hintWithPreview": "Show calculated price per {{quantity}} {{unit}}. For most products use 1 (for example: 1 kg, 1 l, 1 m²).",
|
|
467
|
+
"catalog.products.unitPrice.options.kg": "1 kg",
|
|
468
|
+
"catalog.products.unitPrice.options.l": "1 l",
|
|
469
|
+
"catalog.products.unitPrice.options.m2": "1 m²",
|
|
470
|
+
"catalog.products.unitPrice.options.m3": "1 m³",
|
|
471
|
+
"catalog.products.unitPrice.options.pc": "1 pc",
|
|
472
|
+
"catalog.products.unitPrice.referenceUnit": "Reference unit",
|
|
473
|
+
"catalog.products.unitPrice.selectReferenceUnit": "Select reference unit",
|
|
474
|
+
"catalog.products.uom.active": "Active",
|
|
475
|
+
"catalog.products.uom.addConversion": "Add conversion",
|
|
476
|
+
"catalog.products.uom.baseUnit": "Base unit",
|
|
477
|
+
"catalog.products.uom.conversionOrderHint": "Use arrows to reorder conversion priority.",
|
|
478
|
+
"catalog.products.uom.conversionPreview": "1 {{fromUnit}} = {{factor}} {{baseUnit}}",
|
|
479
|
+
"catalog.products.uom.conversionUnit": "Sales unit",
|
|
480
|
+
"catalog.products.uom.conversions": "Product conversions",
|
|
481
|
+
"catalog.products.uom.defaultSalesQuantity": "Default sales quantity",
|
|
482
|
+
"catalog.products.uom.defaultSalesQuantityHint": "Used to prefill quantity in quote/order lines. Value is interpreted in Default sales unit.",
|
|
483
|
+
"catalog.products.uom.defaultSalesQuantityLabel": "Default line quantity (in sales unit)",
|
|
484
|
+
"catalog.products.uom.defaultSalesQuantityPreview": "Default line: {{quantity}} {{salesUnit}}.",
|
|
485
|
+
"catalog.products.uom.defaultSalesQuantityPreviewWithNormalization": "Default line: {{quantity}} {{salesUnit}} (= {{normalized}} {{baseUnit}}).",
|
|
486
|
+
"catalog.products.uom.defaultSalesUnit": "Default sales unit",
|
|
487
|
+
"catalog.products.uom.description": "Set base/sales units and packaging conversions.",
|
|
488
|
+
"catalog.products.uom.emptyConversions": "No conversions configured yet.",
|
|
489
|
+
"catalog.products.uom.errors.baseRequired": "Base unit is required when default sales unit is set.",
|
|
490
|
+
"catalog.products.uom.errors.baseRequiredForConversions": "Base unit is required when conversions are configured.",
|
|
491
|
+
"catalog.products.uom.errors.defaultSalesConversionRequired": "Active conversion for default sales unit is required when it differs from base unit.",
|
|
492
|
+
"catalog.products.uom.errors.duplicateConversion": "Duplicate conversion unit is not allowed.",
|
|
493
|
+
"catalog.products.uom.errors.loadUnits": "Failed to load units. Please try refreshing the page.",
|
|
494
|
+
"catalog.products.uom.errors.sync": "Failed to synchronize product conversions.",
|
|
495
|
+
"catalog.products.uom.loadingUnits": "Loading units...",
|
|
496
|
+
"catalog.products.uom.moveDown": "Move conversion down",
|
|
497
|
+
"catalog.products.uom.moveUp": "Move conversion up",
|
|
498
|
+
"catalog.products.uom.removeConversion": "Remove conversion",
|
|
499
|
+
"catalog.products.uom.roundingMode": "Rounding mode",
|
|
500
|
+
"catalog.products.uom.roundingModeDown": "Down",
|
|
501
|
+
"catalog.products.uom.roundingModeHalfUp": "Half up",
|
|
502
|
+
"catalog.products.uom.roundingModeUp": "Up",
|
|
503
|
+
"catalog.products.uom.roundingScale": "Rounding scale",
|
|
504
|
+
"catalog.products.uom.selectUnit": "Select unit",
|
|
505
|
+
"catalog.products.uom.sortOrder": "Sort",
|
|
506
|
+
"catalog.products.uom.title": "Units of measure",
|
|
507
|
+
"catalog.products.uom.toBaseFactor": "To base factor",
|
|
508
|
+
"catalog.products.validation.baseUnitRequired": "Base unit is required when a default sales unit is set.",
|
|
509
|
+
"catalog.products.validation.handleFormat": "Handle must include lowercase letters, digits, hyphen, or underscore.",
|
|
510
|
+
"catalog.products.validation.referenceUnitRequired": "Reference unit is required when unit price display is enabled.",
|
|
511
|
+
"catalog.products.validation.titleRequired": "Title is required.",
|
|
457
512
|
"catalog.search.badge.category": "Category",
|
|
458
513
|
"catalog.search.badge.offer": "Channel Offer",
|
|
459
514
|
"catalog.search.badge.optionSchema": "Option Schema",
|
|
460
515
|
"catalog.search.badge.priceKind": "Price Kind",
|
|
461
516
|
"catalog.search.badge.product": "Product",
|
|
462
517
|
"catalog.search.badge.tag": "Tag",
|
|
518
|
+
"catalog.search.badge.unitConversion": "Unit Conversion",
|
|
463
519
|
"catalog.search.badge.variant": "Variant",
|
|
464
520
|
"catalog.search.priceKind.excludingTax": "Excl. tax",
|
|
465
521
|
"catalog.search.priceKind.includingTax": "Incl. tax",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"catalog.audit.prices.create": "Crear precio",
|
|
17
17
|
"catalog.audit.prices.delete": "Eliminar precio",
|
|
18
18
|
"catalog.audit.prices.update": "Actualizar precio",
|
|
19
|
+
"catalog.audit.productUnitConversions.create": "Crear conversión de unidad de producto",
|
|
20
|
+
"catalog.audit.productUnitConversions.delete": "Eliminar conversión de unidad de producto",
|
|
21
|
+
"catalog.audit.productUnitConversions.update": "Actualizar conversión de unidad de producto",
|
|
19
22
|
"catalog.audit.products.create": "Crear producto",
|
|
20
23
|
"catalog.audit.products.delete": "Eliminar producto",
|
|
21
24
|
"catalog.audit.products.update": "Actualizar producto",
|
|
@@ -394,6 +397,7 @@
|
|
|
394
397
|
"catalog.products.edit.weight.value": "Peso",
|
|
395
398
|
"catalog.products.errors.handleExists": "El identificador ya está en uso.",
|
|
396
399
|
"catalog.products.errors.skuExists": "El SKU ya está en uso.",
|
|
400
|
+
"catalog.products.errors.taxClassNotFound": "Clase de impuesto no encontrada.",
|
|
397
401
|
"catalog.products.filters.active": "Activo",
|
|
398
402
|
"catalog.products.filters.categories": "Categorías",
|
|
399
403
|
"catalog.products.filters.categoriesLoadError": "No se pudieron cargar las categorías",
|
|
@@ -454,12 +458,64 @@
|
|
|
454
458
|
"catalog.products.types.grouped": "Agrupado",
|
|
455
459
|
"catalog.products.types.simple": "Simple",
|
|
456
460
|
"catalog.products.types.virtual": "Virtual",
|
|
461
|
+
"catalog.products.unitPrice.baseQuantity": "Cantidad base de referencia",
|
|
462
|
+
"catalog.products.unitPrice.enable": "Activar precio unitario UE",
|
|
463
|
+
"catalog.products.unitPrice.errors.baseQuantity": "La cantidad base es obligatoria cuando la visualización del precio unitario está activada.",
|
|
464
|
+
"catalog.products.unitPrice.errors.referenceUnit": "La unidad de referencia es obligatoria cuando la visualización del precio unitario está activada.",
|
|
465
|
+
"catalog.products.unitPrice.hint": "Muestra el precio calculado por la unidad de referencia seleccionada. En la mayoría de casos usa cantidad 1.",
|
|
466
|
+
"catalog.products.unitPrice.hintWithPreview": "Muestra el precio calculado por {{quantity}} {{unit}}. Para la mayoría de productos usa 1 (por ejemplo: 1 kg, 1 l, 1 m²).",
|
|
467
|
+
"catalog.products.unitPrice.options.kg": "1 kg",
|
|
468
|
+
"catalog.products.unitPrice.options.l": "1 l",
|
|
469
|
+
"catalog.products.unitPrice.options.m2": "1 m²",
|
|
470
|
+
"catalog.products.unitPrice.options.m3": "1 m³",
|
|
471
|
+
"catalog.products.unitPrice.options.pc": "1 ud.",
|
|
472
|
+
"catalog.products.unitPrice.referenceUnit": "Unidad de referencia",
|
|
473
|
+
"catalog.products.unitPrice.selectReferenceUnit": "Seleccionar unidad de referencia",
|
|
474
|
+
"catalog.products.uom.active": "Activo",
|
|
475
|
+
"catalog.products.uom.addConversion": "Añadir conversión",
|
|
476
|
+
"catalog.products.uom.baseUnit": "Unidad base",
|
|
477
|
+
"catalog.products.uom.conversionOrderHint": "Usa las flechas para reordenar la prioridad de conversión.",
|
|
478
|
+
"catalog.products.uom.conversionPreview": "1 {{fromUnit}} = {{factor}} {{baseUnit}}",
|
|
479
|
+
"catalog.products.uom.conversionUnit": "Unidad de venta",
|
|
480
|
+
"catalog.products.uom.conversions": "Conversiones de producto",
|
|
481
|
+
"catalog.products.uom.defaultSalesQuantity": "Cantidad de venta predeterminada",
|
|
482
|
+
"catalog.products.uom.defaultSalesQuantityHint": "Se usa para rellenar la cantidad en líneas de oferta/pedido. El valor se interpreta en la unidad de venta predeterminada.",
|
|
483
|
+
"catalog.products.uom.defaultSalesQuantityLabel": "Cantidad predeterminada de línea (en unidad de venta)",
|
|
484
|
+
"catalog.products.uom.defaultSalesQuantityPreview": "Línea predeterminada: {{quantity}} {{salesUnit}}.",
|
|
485
|
+
"catalog.products.uom.defaultSalesQuantityPreviewWithNormalization": "Línea predeterminada: {{quantity}} {{salesUnit}} (= {{normalized}} {{baseUnit}}).",
|
|
486
|
+
"catalog.products.uom.defaultSalesUnit": "Unidad de venta predeterminada",
|
|
487
|
+
"catalog.products.uom.description": "Configurar unidades base/venta y conversiones de empaque.",
|
|
488
|
+
"catalog.products.uom.emptyConversions": "Aún no hay conversiones configuradas.",
|
|
489
|
+
"catalog.products.uom.errors.baseRequired": "La unidad base es obligatoria cuando se establece una unidad de venta predeterminada.",
|
|
490
|
+
"catalog.products.uom.errors.baseRequiredForConversions": "La unidad base es obligatoria cuando hay conversiones configuradas.",
|
|
491
|
+
"catalog.products.uom.errors.defaultSalesConversionRequired": "Se requiere una conversión activa para la unidad de venta predeterminada cuando difiere de la unidad base.",
|
|
492
|
+
"catalog.products.uom.errors.duplicateConversion": "No se permite una unidad de conversión duplicada.",
|
|
493
|
+
"catalog.products.uom.errors.loadUnits": "No se pudieron cargar las unidades. Intente actualizar la página.",
|
|
494
|
+
"catalog.products.uom.errors.sync": "No se pudieron sincronizar las conversiones de producto.",
|
|
495
|
+
"catalog.products.uom.loadingUnits": "Cargando unidades...",
|
|
496
|
+
"catalog.products.uom.moveDown": "Mover conversión hacia abajo",
|
|
497
|
+
"catalog.products.uom.moveUp": "Mover conversión hacia arriba",
|
|
498
|
+
"catalog.products.uom.removeConversion": "Eliminar conversión",
|
|
499
|
+
"catalog.products.uom.roundingMode": "Modo de redondeo",
|
|
500
|
+
"catalog.products.uom.roundingModeDown": "Redondeo hacia abajo",
|
|
501
|
+
"catalog.products.uom.roundingModeHalfUp": "Redondeo comercial (predeterminado)",
|
|
502
|
+
"catalog.products.uom.roundingModeUp": "Redondeo hacia arriba",
|
|
503
|
+
"catalog.products.uom.roundingScale": "Precisión de redondeo (decimales)",
|
|
504
|
+
"catalog.products.uom.selectUnit": "Seleccionar unidad",
|
|
505
|
+
"catalog.products.uom.sortOrder": "Orden",
|
|
506
|
+
"catalog.products.uom.title": "Unidades de medida",
|
|
507
|
+
"catalog.products.uom.toBaseFactor": "Factor base",
|
|
508
|
+
"catalog.products.validation.baseUnitRequired": "La unidad base es obligatoria cuando se establece una unidad de venta predeterminada.",
|
|
509
|
+
"catalog.products.validation.handleFormat": "El identificador solo puede contener letras minúsculas, dígitos, guiones o guiones bajos.",
|
|
510
|
+
"catalog.products.validation.referenceUnitRequired": "La unidad de referencia es obligatoria cuando la visualización del precio unitario está activada.",
|
|
511
|
+
"catalog.products.validation.titleRequired": "El título es obligatorio.",
|
|
457
512
|
"catalog.search.badge.category": "Categoría",
|
|
458
513
|
"catalog.search.badge.offer": "Oferta de canal",
|
|
459
514
|
"catalog.search.badge.optionSchema": "Esquema de opciones",
|
|
460
515
|
"catalog.search.badge.priceKind": "Tipo de precio",
|
|
461
516
|
"catalog.search.badge.product": "Producto",
|
|
462
517
|
"catalog.search.badge.tag": "Etiqueta",
|
|
518
|
+
"catalog.search.badge.unitConversion": "Conversión de unidad",
|
|
463
519
|
"catalog.search.badge.variant": "Variante",
|
|
464
520
|
"catalog.search.priceKind.excludingTax": "Excl. impuestos",
|
|
465
521
|
"catalog.search.priceKind.includingTax": "Incl. impuestos",
|