@open-mercato/core 0.6.6-develop.6309.1.983aeec27a → 0.6.6-develop.6314.1.c7b8291aa2
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/helpers/integration/salesFixtures.js +10 -0
- package/dist/helpers/integration/salesFixtures.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +92 -37
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +7 -1
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/lib/dictionaries.js +10 -0
- package/dist/modules/customers/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +38 -3
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +18 -5
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/lib/returnQuantity.js +29 -2
- package/dist/modules/sales/lib/returnQuantity.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/package.json +7 -7
- package/src/helpers/integration/salesFixtures.ts +21 -0
- package/src/modules/customers/components/DictionarySettings.tsx +60 -2
- package/src/modules/customers/components/formConfig.tsx +8 -2
- package/src/modules/customers/lib/dictionaries.ts +10 -0
- package/src/modules/sales/commands/returns.ts +44 -3
- package/src/modules/sales/components/documents/ReturnDialog.tsx +1 -0
- package/src/modules/sales/components/documents/ReturnsSection.tsx +18 -5
- package/src/modules/sales/i18n/de.json +1 -0
- package/src/modules/sales/i18n/en.json +1 -0
- package/src/modules/sales/i18n/es.json +1 -0
- package/src/modules/sales/i18n/pl.json +1 -0
- package/src/modules/sales/lib/returnQuantity.ts +48 -1
- package/src/modules/workflows/lib/event-trigger-service.ts +3 -0
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
emitSalesDocumentTotalsRefresh,
|
|
18
18
|
subscribeSalesDocumentTotalsRefresh,
|
|
19
19
|
} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'
|
|
20
|
+
import { sumShippedQuantityByLine } from '@open-mercato/core/modules/sales/lib/returnQuantity'
|
|
20
21
|
import { formatMoney, normalizeNumber } from './lineItemUtils'
|
|
21
22
|
import { ReturnDialog, type ReturnOrderLine } from './ReturnDialog'
|
|
22
23
|
import { ReturnEditDialog, type ReturnEditRecord } from './ReturnEditDialog'
|
|
@@ -60,14 +61,25 @@ export function SalesReturnsSection({ orderId, currencyCode, documentUpdatedAt }
|
|
|
60
61
|
|
|
61
62
|
const loadLines = React.useCallback(async () => {
|
|
62
63
|
const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const shipmentParams = new URLSearchParams({ page: '1', pageSize: '200', orderId })
|
|
65
|
+
const [response, shipmentsResponse] = await Promise.all([
|
|
66
|
+
apiCall<{ items?: Array<Record<string, unknown>> }>(
|
|
67
|
+
`/api/sales/order-lines?${params.toString()}`,
|
|
68
|
+
undefined,
|
|
69
|
+
{ fallback: { items: [] } },
|
|
70
|
+
),
|
|
71
|
+
apiCall<{ items?: Array<Record<string, unknown>> }>(
|
|
72
|
+
`/api/sales/shipments?${shipmentParams.toString()}`,
|
|
73
|
+
undefined,
|
|
74
|
+
{ fallback: { items: [] } },
|
|
75
|
+
),
|
|
76
|
+
])
|
|
77
|
+
const shippedByLine = sumShippedQuantityByLine(
|
|
78
|
+
Array.isArray(shipmentsResponse.result?.items) ? shipmentsResponse.result?.items : [],
|
|
67
79
|
)
|
|
68
80
|
const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []
|
|
69
81
|
const mapped: ReturnOrderLine[] = items
|
|
70
|
-
.map((item) => {
|
|
82
|
+
.map((item): ReturnOrderLine | null => {
|
|
71
83
|
const map = item as Record<string, unknown>
|
|
72
84
|
const id = typeof map.id === 'string' ? map.id : null
|
|
73
85
|
if (!id) return null
|
|
@@ -110,6 +122,7 @@ export function SalesReturnsSection({ orderId, currencyCode, documentUpdatedAt }
|
|
|
110
122
|
lineNumber,
|
|
111
123
|
quantity: Number.isFinite(quantity) ? quantity : 0,
|
|
112
124
|
returnedQuantity: Number.isFinite(returnedQuantity) ? returnedQuantity : 0,
|
|
125
|
+
shippedQuantity: shippedByLine.get(id) ?? 0,
|
|
113
126
|
}
|
|
114
127
|
})
|
|
115
128
|
.filter((entry): entry is ReturnOrderLine => Boolean(entry?.id))
|
|
@@ -1326,6 +1326,7 @@
|
|
|
1326
1326
|
"sales.returns.qty.increase": "Menge erhöhen",
|
|
1327
1327
|
"sales.returns.quantity": "Menge",
|
|
1328
1328
|
"sales.returns.quantityExceeded": "Es kann nicht mehr als die verbleibende Menge zurückgegeben werden.",
|
|
1329
|
+
"sales.returns.quantityExceedsShipped": "Es kann nicht mehr als die versandte Menge zurückgegeben werden. Versenden Sie die Artikel, bevor Sie eine Rücksendung erfassen.",
|
|
1329
1330
|
"sales.returns.reason": "Grund",
|
|
1330
1331
|
"sales.returns.reason.placeholder": "Optional",
|
|
1331
1332
|
"sales.returns.returnNumber": "Rückgabe",
|
|
@@ -1326,6 +1326,7 @@
|
|
|
1326
1326
|
"sales.returns.qty.increase": "Increase quantity",
|
|
1327
1327
|
"sales.returns.quantity": "Quantity",
|
|
1328
1328
|
"sales.returns.quantityExceeded": "Cannot return more than the remaining quantity.",
|
|
1329
|
+
"sales.returns.quantityExceedsShipped": "Cannot return more than the shipped quantity. Ship the items before recording a return.",
|
|
1329
1330
|
"sales.returns.reason": "Reason",
|
|
1330
1331
|
"sales.returns.reason.placeholder": "Optional",
|
|
1331
1332
|
"sales.returns.returnNumber": "Return",
|
|
@@ -1326,6 +1326,7 @@
|
|
|
1326
1326
|
"sales.returns.qty.increase": "Aumentar cantidad",
|
|
1327
1327
|
"sales.returns.quantity": "Cantidad",
|
|
1328
1328
|
"sales.returns.quantityExceeded": "No se puede devolver más que la cantidad restante.",
|
|
1329
|
+
"sales.returns.quantityExceedsShipped": "No se puede devolver más que la cantidad enviada. Envíe los artículos antes de registrar una devolución.",
|
|
1329
1330
|
"sales.returns.reason": "Motivo",
|
|
1330
1331
|
"sales.returns.reason.placeholder": "Opcional",
|
|
1331
1332
|
"sales.returns.returnNumber": "Devolución",
|
|
@@ -1326,6 +1326,7 @@
|
|
|
1326
1326
|
"sales.returns.qty.increase": "Zwiększ ilość",
|
|
1327
1327
|
"sales.returns.quantity": "Ilość",
|
|
1328
1328
|
"sales.returns.quantityExceeded": "Nie można zwrócić więcej niż pozostała ilość.",
|
|
1329
|
+
"sales.returns.quantityExceedsShipped": "Nie można zwrócić więcej niż wysłana ilość. Wyślij artykuły, zanim zarejestrujesz zwrot.",
|
|
1329
1330
|
"sales.returns.reason": "Powód",
|
|
1330
1331
|
"sales.returns.reason.placeholder": "Opcjonalny",
|
|
1331
1332
|
"sales.returns.returnNumber": "Zwrot",
|
|
@@ -1,10 +1,57 @@
|
|
|
1
1
|
export type ReturnAvailableInput = {
|
|
2
2
|
quantity: number
|
|
3
3
|
returnedQuantity: number
|
|
4
|
+
shippedQuantity?: number
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
export function computeAvailableReturnQuantity(line: ReturnAvailableInput): number {
|
|
7
|
-
const
|
|
8
|
+
const cap =
|
|
9
|
+
typeof line.shippedQuantity === 'number' && Number.isFinite(line.shippedQuantity)
|
|
10
|
+
? Math.min(line.quantity, line.shippedQuantity)
|
|
11
|
+
: line.quantity
|
|
12
|
+
const raw = cap - line.returnedQuantity
|
|
8
13
|
if (!Number.isFinite(raw) || raw <= 0) return 0
|
|
9
14
|
return Math.max(0, Math.floor(raw + 1e-6))
|
|
10
15
|
}
|
|
16
|
+
|
|
17
|
+
function coerceQuantity(value: unknown): number {
|
|
18
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value
|
|
19
|
+
if (typeof value === 'string' && value.trim().length) {
|
|
20
|
+
const parsed = Number(value)
|
|
21
|
+
if (Number.isFinite(parsed)) return parsed
|
|
22
|
+
}
|
|
23
|
+
return 0
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Aggregate shipped quantity per order line from the `/api/sales/shipments`
|
|
28
|
+
* list payload. Mirrors the server-side `loadShippedQuantityByLine` cap so the
|
|
29
|
+
* Return dialog's "Available" figure matches what `sales.returns.create`
|
|
30
|
+
* enforces. Each shipment exposes its lines under `items` (either the
|
|
31
|
+
* persisted snapshot or DB-grouped rows), both carrying `orderLineId` and
|
|
32
|
+
* `quantity`.
|
|
33
|
+
*/
|
|
34
|
+
export function sumShippedQuantityByLine(
|
|
35
|
+
shipments: ReadonlyArray<Record<string, unknown>> | null | undefined,
|
|
36
|
+
): Map<string, number> {
|
|
37
|
+
const shippedByLine = new Map<string, number>()
|
|
38
|
+
if (!Array.isArray(shipments)) return shippedByLine
|
|
39
|
+
for (const shipment of shipments) {
|
|
40
|
+
if (!shipment || typeof shipment !== 'object') continue
|
|
41
|
+
const lineItems = (shipment as Record<string, unknown>).items
|
|
42
|
+
if (!Array.isArray(lineItems)) continue
|
|
43
|
+
for (const lineItem of lineItems) {
|
|
44
|
+
if (!lineItem || typeof lineItem !== 'object') continue
|
|
45
|
+
const record = lineItem as Record<string, unknown>
|
|
46
|
+
const orderLineId =
|
|
47
|
+
typeof record.orderLineId === 'string'
|
|
48
|
+
? record.orderLineId
|
|
49
|
+
: typeof record.order_line_id === 'string'
|
|
50
|
+
? record.order_line_id
|
|
51
|
+
: null
|
|
52
|
+
if (!orderLineId) continue
|
|
53
|
+
shippedByLine.set(orderLineId, (shippedByLine.get(orderLineId) ?? 0) + coerceQuantity(record.quantity))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return shippedByLine
|
|
57
|
+
}
|
|
@@ -123,6 +123,9 @@ function isSafeWorkflowRegexPattern(pattern: string): boolean {
|
|
|
123
123
|
let lastClosedGroup: RegexGroupFrame | null = null
|
|
124
124
|
let lastAtomWasQuantified = false
|
|
125
125
|
|
|
126
|
+
// Hand-written single-pass lexer: `index` is intentionally advanced inside the
|
|
127
|
+
// loop body (escape pairs, `(?:` prefixes, multi-char quantifiers, lazy `?`) on
|
|
128
|
+
// top of the `index += 1` update clause. Do not "simplify" these in-body writes.
|
|
126
129
|
for (let index = 0; index < pattern.length; index += 1) {
|
|
127
130
|
const char = pattern[index]
|
|
128
131
|
|