@open-mercato/core 0.4.8-develop-d16e2f51dc → 0.4.8-develop-4b58cde65d

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.
Files changed (85) hide show
  1. package/dist/generated/entities/sales_return/index.js +31 -0
  2. package/dist/generated/entities/sales_return/index.js.map +7 -0
  3. package/dist/generated/entities/sales_return_line/index.js +29 -0
  4. package/dist/generated/entities/sales_return_line/index.js.map +7 -0
  5. package/dist/generated/entities.ids.generated.js +2 -0
  6. package/dist/generated/entities.ids.generated.js.map +2 -2
  7. package/dist/generated/entity-fields-registry.js +4 -0
  8. package/dist/generated/entity-fields-registry.js.map +2 -2
  9. package/dist/modules/sales/acl.js +2 -0
  10. package/dist/modules/sales/acl.js.map +2 -2
  11. package/dist/modules/sales/api/document-history/route.js +20 -2
  12. package/dist/modules/sales/api/document-history/route.js.map +2 -2
  13. package/dist/modules/sales/api/documents/factory.js +34 -0
  14. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  15. package/dist/modules/sales/api/returns/[id]/route.js +147 -0
  16. package/dist/modules/sales/api/returns/[id]/route.js.map +7 -0
  17. package/dist/modules/sales/api/returns/route.js +158 -0
  18. package/dist/modules/sales/api/returns/route.js.map +7 -0
  19. package/dist/modules/sales/backend/sales/documents/[id]/page.js +20 -1
  20. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  21. package/dist/modules/sales/commands/index.js +1 -0
  22. package/dist/modules/sales/commands/index.js.map +2 -2
  23. package/dist/modules/sales/commands/returns.js +467 -0
  24. package/dist/modules/sales/commands/returns.js.map +7 -0
  25. package/dist/modules/sales/components/documents/ReturnDialog.js +176 -0
  26. package/dist/modules/sales/components/documents/ReturnDialog.js.map +7 -0
  27. package/dist/modules/sales/components/documents/ReturnsSection.js +188 -0
  28. package/dist/modules/sales/components/documents/ReturnsSection.js.map +7 -0
  29. package/dist/modules/sales/data/entities.js +115 -1
  30. package/dist/modules/sales/data/entities.js.map +2 -2
  31. package/dist/modules/sales/data/validators.js +13 -0
  32. package/dist/modules/sales/data/validators.js.map +2 -2
  33. package/dist/modules/sales/events.js +4 -0
  34. package/dist/modules/sales/events.js.map +2 -2
  35. package/dist/modules/sales/lib/calculations.js +7 -0
  36. package/dist/modules/sales/lib/calculations.js.map +2 -2
  37. package/dist/modules/sales/lib/dictionaries.js +1 -0
  38. package/dist/modules/sales/lib/dictionaries.js.map +2 -2
  39. package/dist/modules/sales/lib/documentNumberTokens.js +2 -0
  40. package/dist/modules/sales/lib/documentNumberTokens.js.map +2 -2
  41. package/dist/modules/sales/lib/historyHelpers.js +15 -7
  42. package/dist/modules/sales/lib/historyHelpers.js.map +2 -2
  43. package/dist/modules/sales/lib/makeSalesLineRoute.js +42 -37
  44. package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
  45. package/dist/modules/sales/migrations/Migration20260309073310.js +23 -0
  46. package/dist/modules/sales/migrations/Migration20260309073310.js.map +7 -0
  47. package/dist/modules/sales/services/salesDocumentNumberGenerator.js +8 -6
  48. package/dist/modules/sales/services/salesDocumentNumberGenerator.js.map +2 -2
  49. package/dist/modules/sales/setup.js +1 -1
  50. package/dist/modules/sales/setup.js.map +2 -2
  51. package/dist/modules/sales/widgets/injection/document-history/widget.client.js +25 -16
  52. package/dist/modules/sales/widgets/injection/document-history/widget.client.js.map +2 -2
  53. package/generated/entities/sales_return/index.ts +14 -0
  54. package/generated/entities/sales_return_line/index.ts +13 -0
  55. package/generated/entities.ids.generated.ts +2 -0
  56. package/generated/entity-fields-registry.ts +4 -0
  57. package/package.json +3 -3
  58. package/src/modules/sales/AGENTS.md +1 -0
  59. package/src/modules/sales/acl.ts +2 -0
  60. package/src/modules/sales/api/document-history/route.ts +25 -1
  61. package/src/modules/sales/api/documents/factory.ts +35 -0
  62. package/src/modules/sales/api/returns/[id]/route.ts +156 -0
  63. package/src/modules/sales/api/returns/route.ts +171 -0
  64. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +18 -0
  65. package/src/modules/sales/commands/index.ts +1 -0
  66. package/src/modules/sales/commands/returns.ts +540 -0
  67. package/src/modules/sales/components/documents/ReturnDialog.tsx +216 -0
  68. package/src/modules/sales/components/documents/ReturnsSection.tsx +270 -0
  69. package/src/modules/sales/data/entities.ts +99 -3
  70. package/src/modules/sales/data/validators.ts +16 -0
  71. package/src/modules/sales/events.ts +5 -0
  72. package/src/modules/sales/i18n/de.json +32 -0
  73. package/src/modules/sales/i18n/en.json +32 -0
  74. package/src/modules/sales/i18n/es.json +32 -0
  75. package/src/modules/sales/i18n/pl.json +32 -0
  76. package/src/modules/sales/lib/calculations.ts +9 -0
  77. package/src/modules/sales/lib/dictionaries.ts +1 -0
  78. package/src/modules/sales/lib/documentNumberTokens.ts +2 -1
  79. package/src/modules/sales/lib/historyHelpers.ts +20 -9
  80. package/src/modules/sales/lib/makeSalesLineRoute.ts +42 -37
  81. package/src/modules/sales/migrations/.snapshot-open-mercato.json +398 -0
  82. package/src/modules/sales/migrations/Migration20260309073310.ts +26 -0
  83. package/src/modules/sales/services/salesDocumentNumberGenerator.ts +15 -4
  84. package/src/modules/sales/setup.ts +1 -1
  85. package/src/modules/sales/widgets/injection/document-history/widget.client.tsx +26 -17
@@ -0,0 +1,176 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
5
+ import { Input } from "@open-mercato/ui/primitives/input";
6
+ import { Textarea } from "@open-mercato/ui/primitives/textarea";
7
+ import { Label } from "@open-mercato/ui/primitives/label";
8
+ import { Button } from "@open-mercato/ui/primitives/button";
9
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
10
+ import { apiCallOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
11
+ import { flash } from "@open-mercato/ui/backend/FlashMessages";
12
+ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
13
+ const normalizeNumber = (value) => {
14
+ if (typeof value === "number" && Number.isFinite(value)) return value;
15
+ if (typeof value === "string" && value.trim().length) {
16
+ const parsed = Number(value);
17
+ if (Number.isFinite(parsed)) return parsed;
18
+ }
19
+ return 0;
20
+ };
21
+ function ReturnDialog({ open, orderId, lines, onClose, onSaved }) {
22
+ const t = useT();
23
+ const { runMutation } = useGuardedMutation({ contextId: `sales-returns-${orderId}` });
24
+ const [reason, setReason] = React.useState("");
25
+ const [notes, setNotes] = React.useState("");
26
+ const [quantities, setQuantities] = React.useState({});
27
+ const [saving, setSaving] = React.useState(false);
28
+ const availableLines = React.useMemo(() => {
29
+ return lines.map((line) => {
30
+ const available = Math.max(0, line.quantity - line.returnedQuantity);
31
+ return { ...line, available };
32
+ }).filter((line) => line.available > 0);
33
+ }, [lines]);
34
+ React.useEffect(() => {
35
+ if (!open) return;
36
+ setReason("");
37
+ setNotes("");
38
+ setQuantities({});
39
+ }, [open]);
40
+ const submit = React.useCallback(async () => {
41
+ if (saving) return;
42
+ let hasInvalidQuantity = false;
43
+ const linesForRequest = [];
44
+ availableLines.forEach((line) => {
45
+ const raw = quantities[line.id];
46
+ const qty = normalizeNumber(raw);
47
+ if (!Number.isFinite(qty) || qty <= 0) return;
48
+ if (qty - 1e-6 > line.available) {
49
+ hasInvalidQuantity = true;
50
+ return;
51
+ }
52
+ linesForRequest.push({ orderLineId: line.id, quantity: qty.toString() });
53
+ });
54
+ if (hasInvalidQuantity) {
55
+ flash(t("sales.returns.errors.quantityExceeded", "Cannot return more than available quantity."), "error");
56
+ return;
57
+ }
58
+ if (!linesForRequest.length) {
59
+ flash(t("sales.returns.errors.linesRequired", "Select at least one line to return."), "error");
60
+ return;
61
+ }
62
+ setSaving(true);
63
+ try {
64
+ await runMutation({
65
+ context: { kind: "order", record: { id: orderId } },
66
+ mutationPayload: { orderId, lines: linesForRequest, reason, notes },
67
+ operation: async () => {
68
+ const response = await apiCallOrThrow(
69
+ "/api/sales/returns",
70
+ {
71
+ method: "POST",
72
+ headers: { "content-type": "application/json" },
73
+ body: JSON.stringify({
74
+ orderId,
75
+ lines: linesForRequest,
76
+ ...reason.trim().length ? { reason: reason.trim() } : {},
77
+ ...notes.trim().length ? { notes: notes.trim() } : {}
78
+ })
79
+ },
80
+ { errorMessage: t("sales.returns.errors.create", "Failed to create return.") }
81
+ );
82
+ return response.result?.id ?? null;
83
+ }
84
+ });
85
+ flash(t("sales.returns.created", "Return created."), "success");
86
+ onClose();
87
+ await onSaved();
88
+ } catch {
89
+ flash(t("sales.returns.errors.create", "Failed to create return."), "error");
90
+ } finally {
91
+ setSaving(false);
92
+ }
93
+ }, [availableLines, notes, onClose, onSaved, orderId, quantities, reason, runMutation, saving, t]);
94
+ const onKeyDown = React.useCallback(
95
+ (e) => {
96
+ if (e.key === "Escape") onClose();
97
+ if ((e.key === "Enter" || e.key === "NumpadEnter") && (e.metaKey || e.ctrlKey)) {
98
+ e.preventDefault();
99
+ submit();
100
+ }
101
+ },
102
+ [onClose, submit]
103
+ );
104
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => !next ? onClose() : void 0, children: /* @__PURE__ */ jsxs(DialogContent, { onKeyDown, className: "max-w-2xl", children: [
105
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("sales.returns.create.title", "Create return") }) }),
106
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
107
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
108
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: t("sales.returns.create.lines", "Lines") }),
109
+ !availableLines.length ? /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("sales.returns.empty.available", "No items available to return.") }) : /* @__PURE__ */ jsx("div", { className: "max-h-[280px] overflow-auto rounded-md border", children: /* @__PURE__ */ jsx("div", { className: "divide-y", children: availableLines.map((line) => {
110
+ const value = quantities[line.id] ?? "";
111
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-3", children: [
112
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
113
+ /* @__PURE__ */ jsxs("div", { className: "truncate text-sm font-medium", children: [
114
+ line.lineNumber ? `#${line.lineNumber} \xB7 ` : "",
115
+ line.title
116
+ ] }),
117
+ /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
118
+ t("sales.returns.available", "Available"),
119
+ ": ",
120
+ line.available
121
+ ] })
122
+ ] }),
123
+ /* @__PURE__ */ jsxs("div", { className: "w-32", children: [
124
+ /* @__PURE__ */ jsx(Label, { className: "sr-only", htmlFor: `return-qty-${line.id}`, children: t("sales.returns.quantity", "Quantity") }),
125
+ /* @__PURE__ */ jsx(
126
+ Input,
127
+ {
128
+ id: `return-qty-${line.id}`,
129
+ inputMode: "decimal",
130
+ placeholder: "0",
131
+ value,
132
+ onChange: (e) => setQuantities((prev) => ({ ...prev, [line.id]: e.target.value }))
133
+ }
134
+ )
135
+ ] })
136
+ ] }, line.id);
137
+ }) }) })
138
+ ] }),
139
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
140
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
141
+ /* @__PURE__ */ jsx(Label, { htmlFor: "return-reason", children: t("sales.returns.reason", "Reason") }),
142
+ /* @__PURE__ */ jsx(
143
+ Input,
144
+ {
145
+ id: "return-reason",
146
+ value: reason,
147
+ onChange: (e) => setReason(e.target.value),
148
+ placeholder: t("sales.returns.reason.placeholder", "Optional")
149
+ }
150
+ )
151
+ ] }),
152
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 md:col-span-2", children: [
153
+ /* @__PURE__ */ jsx(Label, { htmlFor: "return-notes", children: t("sales.returns.notes", "Notes") }),
154
+ /* @__PURE__ */ jsx(
155
+ Textarea,
156
+ {
157
+ id: "return-notes",
158
+ value: notes,
159
+ onChange: (e) => setNotes(e.target.value),
160
+ placeholder: t("sales.returns.notes.placeholder", "Optional"),
161
+ rows: 3
162
+ }
163
+ )
164
+ ] })
165
+ ] }),
166
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
167
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onClose, disabled: saving, children: t("common.cancel", "Cancel") }),
168
+ /* @__PURE__ */ jsx(Button, { type: "button", onClick: submit, disabled: saving || !availableLines.length, children: saving ? t("common.saving", "Saving\u2026") : t("sales.returns.create.submit", "Create return") })
169
+ ] })
170
+ ] })
171
+ ] }) });
172
+ }
173
+ export {
174
+ ReturnDialog
175
+ };
176
+ //# sourceMappingURL=ReturnDialog.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/sales/components/documents/ReturnDialog.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\n\nexport type ReturnOrderLine = {\n id: string\n title: string\n lineNumber: number | null\n quantity: number\n returnedQuantity: number\n thumbnail?: string | null\n}\n\ntype ReturnDialogProps = {\n open: boolean\n orderId: string\n lines: ReturnOrderLine[]\n onClose: () => void\n onSaved: () => Promise<void>\n}\n\nconst normalizeNumber = (value: unknown): number => {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n if (Number.isFinite(parsed)) return parsed\n }\n return 0\n}\n\nexport function ReturnDialog({ open, orderId, lines, onClose, onSaved }: ReturnDialogProps) {\n const t = useT()\n const { runMutation } = useGuardedMutation({ contextId: `sales-returns-${orderId}` })\n const [reason, setReason] = React.useState('')\n const [notes, setNotes] = React.useState('')\n const [quantities, setQuantities] = React.useState<Record<string, string>>({})\n const [saving, setSaving] = React.useState(false)\n\n const availableLines = React.useMemo(() => {\n return lines\n .map((line) => {\n const available = Math.max(0, line.quantity - line.returnedQuantity)\n return { ...line, available }\n })\n .filter((line) => line.available > 0)\n }, [lines])\n\n React.useEffect(() => {\n if (!open) return\n setReason('')\n setNotes('')\n setQuantities({})\n }, [open])\n\n const submit = React.useCallback(async () => {\n if (saving) return\n let hasInvalidQuantity = false\n const linesForRequest: Array<{ orderLineId: string; quantity: string }> = []\n availableLines.forEach((line) => {\n const raw = quantities[line.id]\n const qty = normalizeNumber(raw)\n if (!Number.isFinite(qty) || qty <= 0) return\n if (qty - 1e-6 > line.available) {\n hasInvalidQuantity = true\n return\n }\n linesForRequest.push({ orderLineId: line.id, quantity: qty.toString() })\n })\n\n if (hasInvalidQuantity) {\n flash(t('sales.returns.errors.quantityExceeded', 'Cannot return more than available quantity.'), 'error')\n return\n }\n\n if (!linesForRequest.length) {\n flash(t('sales.returns.errors.linesRequired', 'Select at least one line to return.'), 'error')\n return\n }\n\n setSaving(true)\n try {\n await runMutation({\n context: { kind: 'order', record: { id: orderId } },\n mutationPayload: { orderId, lines: linesForRequest, reason, notes },\n operation: async () => {\n const response = await apiCallOrThrow<{ id: string | null }>(\n '/api/sales/returns',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n orderId,\n lines: linesForRequest,\n ...(reason.trim().length ? { reason: reason.trim() } : {}),\n ...(notes.trim().length ? { notes: notes.trim() } : {}),\n }),\n },\n { errorMessage: t('sales.returns.errors.create', 'Failed to create return.') },\n )\n return response.result?.id ?? null\n },\n })\n flash(t('sales.returns.created', 'Return created.'), 'success')\n onClose()\n await onSaved()\n } catch {\n flash(t('sales.returns.errors.create', 'Failed to create return.'), 'error')\n } finally {\n setSaving(false)\n }\n }, [availableLines, notes, onClose, onSaved, orderId, quantities, reason, runMutation, saving, t])\n\n const onKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') onClose()\n if ((e.key === 'Enter' || e.key === 'NumpadEnter') && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n submit()\n }\n },\n [onClose, submit],\n )\n\n return (\n <Dialog open={open} onOpenChange={(next) => (!next ? onClose() : undefined)}>\n <DialogContent onKeyDown={onKeyDown} className=\"max-w-2xl\">\n <DialogHeader>\n <DialogTitle>{t('sales.returns.create.title', 'Create return')}</DialogTitle>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <div className=\"text-sm font-medium\">{t('sales.returns.create.lines', 'Lines')}</div>\n {!availableLines.length ? (\n <div className=\"text-sm text-muted-foreground\">{t('sales.returns.empty.available', 'No items available to return.')}</div>\n ) : (\n <div className=\"max-h-[280px] overflow-auto rounded-md border\">\n <div className=\"divide-y\">\n {availableLines.map((line) => {\n const value = quantities[line.id] ?? ''\n return (\n <div key={line.id} className=\"flex items-center gap-3 p-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium\">\n {line.lineNumber ? `#${line.lineNumber} \u00B7 ` : ''}\n {line.title}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {t('sales.returns.available', 'Available')}: {line.available}\n </div>\n </div>\n <div className=\"w-32\">\n <Label className=\"sr-only\" htmlFor={`return-qty-${line.id}`}>\n {t('sales.returns.quantity', 'Quantity')}\n </Label>\n <Input\n id={`return-qty-${line.id}`}\n inputMode=\"decimal\"\n placeholder=\"0\"\n value={value}\n onChange={(e) => setQuantities((prev) => ({ ...prev, [line.id]: e.target.value }))}\n />\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )}\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"return-reason\">{t('sales.returns.reason', 'Reason')}</Label>\n <Input\n id=\"return-reason\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n placeholder={t('sales.returns.reason.placeholder', 'Optional')}\n />\n </div>\n <div className=\"space-y-1.5 md:col-span-2\">\n <Label htmlFor=\"return-notes\">{t('sales.returns.notes', 'Notes')}</Label>\n <Textarea\n id=\"return-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder={t('sales.returns.notes.placeholder', 'Optional')}\n rows={3}\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={saving}>\n {t('common.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={submit} disabled={saving || !availableLines.length}>\n {saving ? t('common.saving', 'Saving\u2026') : t('sales.returns.create.submit', 'Create return')}\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n )\n}\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,188 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Undo2, Plus } from "lucide-react";
5
+ import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { Badge } from "@open-mercato/ui/primitives/badge";
7
+ import { ErrorMessage, LoadingMessage, TabEmptyState } from "@open-mercato/ui/backend/detail";
8
+ import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
9
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
10
+ import {
11
+ emitSalesDocumentTotalsRefresh,
12
+ subscribeSalesDocumentTotalsRefresh
13
+ } from "@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents";
14
+ import { formatMoney, normalizeNumber } from "./lineItemUtils.js";
15
+ import { ReturnDialog } from "./ReturnDialog.js";
16
+ function formatDisplayDate(value) {
17
+ if (!value) return null;
18
+ const date = new Date(value);
19
+ if (Number.isNaN(date.getTime())) return null;
20
+ return new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(date);
21
+ }
22
+ function SalesReturnsSection({ orderId, currencyCode }) {
23
+ const t = useT();
24
+ const [returns, setReturns] = React.useState([]);
25
+ const [lines, setLines] = React.useState([]);
26
+ const [loading, setLoading] = React.useState(false);
27
+ const [error, setError] = React.useState(null);
28
+ const [dialogOpen, setDialogOpen] = React.useState(false);
29
+ const loadLines = React.useCallback(async () => {
30
+ const params = new URLSearchParams({ page: "1", pageSize: "100", orderId });
31
+ const response = await apiCall(
32
+ `/api/sales/order-lines?${params.toString()}`,
33
+ void 0,
34
+ { fallback: { items: [] } }
35
+ );
36
+ const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : [];
37
+ const mapped = items.map((item) => {
38
+ const map = item;
39
+ const id = typeof map.id === "string" ? map.id : null;
40
+ if (!id) return null;
41
+ const snapshot = map["catalog_snapshot"];
42
+ const snapshotName = snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) ? snapshot["name"] : null;
43
+ const name = typeof map.name === "string" ? map.name : typeof snapshotName === "string" ? snapshotName : null;
44
+ const lineNumber = typeof map["line_number"] === "number" ? map["line_number"] : typeof map.lineNumber === "number" ? map.lineNumber : null;
45
+ const quantity = typeof map.quantity === "number" ? map.quantity : typeof map.quantity === "string" ? Number(map.quantity) : 0;
46
+ const returnedQuantity = typeof map["returned_quantity"] === "number" ? map["returned_quantity"] : typeof map.returnedQuantity === "number" ? map.returnedQuantity : typeof map["returned_quantity"] === "string" ? Number(map["returned_quantity"]) : typeof map.returnedQuantity === "string" ? Number(map.returnedQuantity) : 0;
47
+ return {
48
+ id,
49
+ title: name ?? id,
50
+ lineNumber,
51
+ quantity: Number.isFinite(quantity) ? quantity : 0,
52
+ returnedQuantity: Number.isFinite(returnedQuantity) ? returnedQuantity : 0
53
+ };
54
+ }).filter((entry) => Boolean(entry?.id));
55
+ setLines(mapped);
56
+ }, [orderId]);
57
+ const loadReturns = React.useCallback(async () => {
58
+ setLoading(true);
59
+ setError(null);
60
+ try {
61
+ const params = new URLSearchParams({ page: "1", pageSize: "100", orderId });
62
+ const response = await apiCall(
63
+ `/api/sales/returns?${params.toString()}`,
64
+ void 0,
65
+ { fallback: { items: [] } }
66
+ );
67
+ const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : [];
68
+ const mapped = items.map((item) => {
69
+ const map = item;
70
+ const id = typeof map.id === "string" ? map.id : null;
71
+ if (!id) return null;
72
+ const returnNumber = typeof map["return_number"] === "string" ? map["return_number"] : typeof map.returnNumber === "string" ? map.returnNumber : id;
73
+ const returnedAt = typeof map["returned_at"] === "string" ? map["returned_at"] : typeof map.returnedAt === "string" ? map.returnedAt : null;
74
+ const totalNetAmount = typeof map["total_net_amount"] === "number" ? map["total_net_amount"] : typeof map.totalNetAmount === "number" ? map.totalNetAmount : null;
75
+ const totalGrossAmount = typeof map["total_gross_amount"] === "number" ? map["total_gross_amount"] : typeof map.totalGrossAmount === "number" ? map.totalGrossAmount : null;
76
+ return {
77
+ id,
78
+ returnNumber,
79
+ status: typeof map.status === "string" ? map.status : null,
80
+ returnedAt,
81
+ totalNetAmount,
82
+ totalGrossAmount
83
+ };
84
+ }).filter((entry) => Boolean(entry?.id));
85
+ setReturns(mapped);
86
+ await loadLines();
87
+ } catch {
88
+ setError(t("sales.returns.errors.load", "Failed to load returns."));
89
+ } finally {
90
+ setLoading(false);
91
+ }
92
+ }, [loadLines, orderId, t]);
93
+ React.useEffect(() => {
94
+ loadReturns();
95
+ }, [loadReturns]);
96
+ React.useEffect(() => {
97
+ return subscribeSalesDocumentTotalsRefresh((detail) => {
98
+ if (detail.documentId !== orderId) return;
99
+ loadReturns();
100
+ });
101
+ }, [loadReturns, orderId]);
102
+ const emptyState = React.useMemo(
103
+ () => ({
104
+ title: t("sales.returns.empty.title", "No returns yet."),
105
+ description: t("sales.returns.empty.description", "Create a return to generate credit adjustments for returned items.")
106
+ }),
107
+ [t]
108
+ );
109
+ const rows = React.useMemo(() => {
110
+ return returns.map((ret) => {
111
+ const total = normalizeNumber(ret.totalGrossAmount ?? ret.totalNetAmount ?? 0, 0);
112
+ return {
113
+ ...ret,
114
+ total
115
+ };
116
+ });
117
+ }, [returns]);
118
+ if (loading) return /* @__PURE__ */ jsx(LoadingMessage, { label: t("sales.returns.loading", "Loading returns\u2026") });
119
+ if (error) return /* @__PURE__ */ jsx(ErrorMessage, { label: error });
120
+ if (!rows.length) {
121
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
122
+ /* @__PURE__ */ jsx(
123
+ TabEmptyState,
124
+ {
125
+ title: emptyState.title,
126
+ description: emptyState.description,
127
+ action: {
128
+ label: t("sales.returns.create", "Create return"),
129
+ icon: /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
130
+ onClick: () => setDialogOpen(true)
131
+ }
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsx(
135
+ ReturnDialog,
136
+ {
137
+ open: dialogOpen,
138
+ orderId,
139
+ lines,
140
+ onClose: () => setDialogOpen(false),
141
+ onSaved: async () => {
142
+ emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: "order" });
143
+ await loadReturns();
144
+ }
145
+ }
146
+ )
147
+ ] });
148
+ }
149
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
150
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsxs(Button, { type: "button", onClick: () => setDialogOpen(true), children: [
151
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4", "aria-hidden": true }),
152
+ t("sales.returns.create", "Create return")
153
+ ] }) }),
154
+ /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border", children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_auto_auto] gap-3 border-b bg-muted/30 px-4 py-2 text-xs font-medium text-muted-foreground", children: [
156
+ /* @__PURE__ */ jsx("div", { children: t("sales.returns.returnNumber", "Return") }),
157
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: t("sales.returns.returnedAt", "Returned at") }),
158
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: t("sales.returns.total", "Total") })
159
+ ] }),
160
+ /* @__PURE__ */ jsx("div", { className: "divide-y", children: rows.map((ret) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_auto_auto] items-center gap-3 px-4 py-3", children: [
161
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
162
+ /* @__PURE__ */ jsx(Undo2, { className: "h-4 w-4 text-muted-foreground", "aria-hidden": true }),
163
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium", children: ret.returnNumber }),
164
+ ret.status ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: ret.status }) : null
165
+ ] }) }),
166
+ /* @__PURE__ */ jsx("div", { className: "whitespace-nowrap text-right text-sm text-muted-foreground", children: formatDisplayDate(ret.returnedAt) ?? t("sales.returns.notSet", "Not set") }),
167
+ /* @__PURE__ */ jsx("div", { className: "whitespace-nowrap text-right text-sm font-medium", children: formatMoney(ret.total, currencyCode ?? null) })
168
+ ] }, ret.id)) })
169
+ ] }),
170
+ /* @__PURE__ */ jsx(
171
+ ReturnDialog,
172
+ {
173
+ open: dialogOpen,
174
+ orderId,
175
+ lines,
176
+ onClose: () => setDialogOpen(false),
177
+ onSaved: async () => {
178
+ emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: "order" });
179
+ await loadReturns();
180
+ }
181
+ }
182
+ )
183
+ ] });
184
+ }
185
+ export {
186
+ SalesReturnsSection
187
+ };
188
+ //# sourceMappingURL=ReturnsSection.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/modules/sales/components/documents/ReturnsSection.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Undo2, Plus } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n emitSalesDocumentTotalsRefresh,\n subscribeSalesDocumentTotalsRefresh,\n} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'\nimport { formatMoney, normalizeNumber } from './lineItemUtils'\nimport { ReturnDialog, type ReturnOrderLine } from './ReturnDialog'\n\ntype ReturnRow = {\n id: string\n returnNumber: string\n status: string | null\n returnedAt: string | null\n totalNetAmount: number | null\n totalGrossAmount: number | null\n}\n\ntype SalesReturnsSectionProps = {\n orderId: string\n currencyCode?: string | null\n}\n\nfunction formatDisplayDate(value: string | null | undefined): string | null {\n if (!value) return null\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return null\n return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(date)\n}\n\nexport function SalesReturnsSection({ orderId, currencyCode }: SalesReturnsSectionProps) {\n const t = useT()\n const [returns, setReturns] = React.useState<ReturnRow[]>([])\n const [lines, setLines] = React.useState<ReturnOrderLine[]>([])\n const [loading, setLoading] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [dialogOpen, setDialogOpen] = React.useState(false)\n\n const loadLines = React.useCallback(async () => {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-lines?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: ReturnOrderLine[] = items\n .map((item) => {\n const map = item as Record<string, unknown>\n const id = typeof map.id === 'string' ? map.id : null\n if (!id) return null\n const snapshot = map['catalog_snapshot']\n const snapshotName =\n snapshot && typeof snapshot === 'object' && !Array.isArray(snapshot)\n ? (snapshot as Record<string, unknown>)['name']\n : null\n const name =\n typeof map.name === 'string'\n ? map.name\n : typeof snapshotName === 'string'\n ? snapshotName\n : null\n const lineNumber =\n typeof map['line_number'] === 'number'\n ? (map['line_number'] as number)\n : typeof map.lineNumber === 'number'\n ? (map.lineNumber as number)\n : null\n const quantity =\n typeof map.quantity === 'number'\n ? (map.quantity as number)\n : typeof map.quantity === 'string'\n ? Number(map.quantity)\n : 0\n const returnedQuantity =\n typeof map['returned_quantity'] === 'number'\n ? (map['returned_quantity'] as number)\n : typeof map.returnedQuantity === 'number'\n ? (map.returnedQuantity as number)\n : typeof map['returned_quantity'] === 'string'\n ? Number(map['returned_quantity'])\n : typeof map.returnedQuantity === 'string'\n ? Number(map.returnedQuantity)\n : 0\n return {\n id,\n title: name ?? id,\n lineNumber,\n quantity: Number.isFinite(quantity) ? quantity : 0,\n returnedQuantity: Number.isFinite(returnedQuantity) ? returnedQuantity : 0,\n }\n })\n .filter((entry): entry is ReturnOrderLine => Boolean(entry?.id))\n setLines(mapped)\n }, [orderId])\n\n const loadReturns = React.useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/returns?${params.toString()}`,\n undefined,\n { fallback: { items: [] } },\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: ReturnRow[] = items\n .map((item) => {\n const map = item as Record<string, unknown>\n const id = typeof map.id === 'string' ? map.id : null\n if (!id) return null\n const returnNumber =\n typeof map['return_number'] === 'string'\n ? (map['return_number'] as string)\n : typeof map.returnNumber === 'string'\n ? (map.returnNumber as string)\n : id\n const returnedAt =\n typeof map['returned_at'] === 'string'\n ? (map['returned_at'] as string)\n : typeof map.returnedAt === 'string'\n ? (map.returnedAt as string)\n : null\n const totalNetAmount =\n typeof map['total_net_amount'] === 'number'\n ? (map['total_net_amount'] as number)\n : typeof map.totalNetAmount === 'number'\n ? (map.totalNetAmount as number)\n : null\n const totalGrossAmount =\n typeof map['total_gross_amount'] === 'number'\n ? (map['total_gross_amount'] as number)\n : typeof map.totalGrossAmount === 'number'\n ? (map.totalGrossAmount as number)\n : null\n return {\n id,\n returnNumber,\n status: typeof map.status === 'string' ? (map.status as string) : null,\n returnedAt,\n totalNetAmount,\n totalGrossAmount,\n }\n })\n .filter((entry): entry is ReturnRow => Boolean(entry?.id))\n setReturns(mapped)\n await loadLines()\n } catch {\n setError(t('sales.returns.errors.load', 'Failed to load returns.'))\n } finally {\n setLoading(false)\n }\n }, [loadLines, orderId, t])\n\n React.useEffect(() => {\n loadReturns()\n }, [loadReturns])\n\n React.useEffect(() => {\n return subscribeSalesDocumentTotalsRefresh((detail) => {\n if (detail.documentId !== orderId) return\n loadReturns()\n })\n }, [loadReturns, orderId])\n\n const emptyState = React.useMemo(\n () => ({\n title: t('sales.returns.empty.title', 'No returns yet.'),\n description: t('sales.returns.empty.description', 'Create a return to generate credit adjustments for returned items.'),\n }),\n [t],\n )\n\n const rows = React.useMemo(() => {\n return returns.map((ret) => {\n const total = normalizeNumber(ret.totalGrossAmount ?? ret.totalNetAmount ?? 0, 0)\n return {\n ...ret,\n total,\n }\n })\n }, [returns])\n\n if (loading) return <LoadingMessage label={t('sales.returns.loading', 'Loading returns\u2026')} />\n if (error) return <ErrorMessage label={error} />\n\n if (!rows.length) {\n return (\n <div className=\"space-y-4\">\n <TabEmptyState\n title={emptyState.title}\n description={emptyState.description}\n action={{\n label: t('sales.returns.create', 'Create return'),\n icon: <Plus className=\"mr-2 h-4 w-4\" aria-hidden />,\n onClick: () => setDialogOpen(true),\n }}\n />\n <ReturnDialog\n open={dialogOpen}\n orderId={orderId}\n lines={lines}\n onClose={() => setDialogOpen(false)}\n onSaved={async () => {\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n await loadReturns()\n }}\n />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-end\">\n <Button type=\"button\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n {t('sales.returns.create', 'Create return')}\n </Button>\n </div>\n\n <div className=\"overflow-hidden rounded-md border\">\n <div className=\"grid grid-cols-[1fr_auto_auto] gap-3 border-b bg-muted/30 px-4 py-2 text-xs font-medium text-muted-foreground\">\n <div>{t('sales.returns.returnNumber', 'Return')}</div>\n <div className=\"text-right\">{t('sales.returns.returnedAt', 'Returned at')}</div>\n <div className=\"text-right\">{t('sales.returns.total', 'Total')}</div>\n </div>\n <div className=\"divide-y\">\n {rows.map((ret) => (\n <div key={ret.id} className=\"grid grid-cols-[1fr_auto_auto] items-center gap-3 px-4 py-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Undo2 className=\"h-4 w-4 text-muted-foreground\" aria-hidden />\n <div className=\"truncate text-sm font-medium\">{ret.returnNumber}</div>\n {ret.status ? <Badge variant=\"secondary\">{ret.status}</Badge> : null}\n </div>\n </div>\n <div className=\"whitespace-nowrap text-right text-sm text-muted-foreground\">\n {formatDisplayDate(ret.returnedAt) ?? t('sales.returns.notSet', 'Not set')}\n </div>\n <div className=\"whitespace-nowrap text-right text-sm font-medium\">\n {formatMoney(ret.total, currencyCode ?? null)}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n <ReturnDialog\n open={dialogOpen}\n orderId={orderId}\n lines={lines}\n onClose={() => setDialogOpen(false)}\n onSaved={async () => {\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n await loadReturns()\n }}\n />\n </div>\n )\n}\n\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -20,7 +20,7 @@ import {
20
20
  Unique
21
21
  } from "@mikro-orm/core";
22
22
  import { DEFAULT_ORDER_NUMBER_FORMAT, DEFAULT_QUOTE_NUMBER_FORMAT } from "../lib/documentNumberTokens.js";
23
- const DEFAULT_SALES_ADJUSTMENT_KINDS = ["discount", "tax", "shipping", "surcharge", "custom"];
23
+ const DEFAULT_SALES_ADJUSTMENT_KINDS = ["discount", "tax", "shipping", "surcharge", "return", "custom"];
24
24
  let SalesChannel = class {
25
25
  constructor() {
26
26
  this.isActive = true;
@@ -1476,6 +1476,118 @@ SalesShipmentItem = __decorateClass([
1476
1476
  Entity({ tableName: "sales_shipment_items" }),
1477
1477
  Index({ name: "sales_shipment_items_scope_idx", properties: ["shipment", "organizationId", "tenantId"] })
1478
1478
  ], SalesShipmentItem);
1479
+ OptionalProps;
1480
+ let SalesReturn = class {
1481
+ constructor() {
1482
+ this.createdAt = /* @__PURE__ */ new Date();
1483
+ this.updatedAt = /* @__PURE__ */ new Date();
1484
+ this.lines = new Collection(this);
1485
+ }
1486
+ };
1487
+ __decorateClass([
1488
+ PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
1489
+ ], SalesReturn.prototype, "id", 2);
1490
+ __decorateClass([
1491
+ ManyToOne(() => SalesOrder, { fieldName: "order_id" })
1492
+ ], SalesReturn.prototype, "order", 2);
1493
+ __decorateClass([
1494
+ Property({ name: "organization_id", type: "uuid" })
1495
+ ], SalesReturn.prototype, "organizationId", 2);
1496
+ __decorateClass([
1497
+ Property({ name: "tenant_id", type: "uuid" })
1498
+ ], SalesReturn.prototype, "tenantId", 2);
1499
+ __decorateClass([
1500
+ Property({ name: "return_number", type: "text" })
1501
+ ], SalesReturn.prototype, "returnNumber", 2);
1502
+ __decorateClass([
1503
+ Property({ name: "status_entry_id", type: "uuid", nullable: true })
1504
+ ], SalesReturn.prototype, "statusEntryId", 2);
1505
+ __decorateClass([
1506
+ Property({ name: "status", type: "text", nullable: true })
1507
+ ], SalesReturn.prototype, "status", 2);
1508
+ __decorateClass([
1509
+ Property({ name: "reason", type: "text", nullable: true })
1510
+ ], SalesReturn.prototype, "reason", 2);
1511
+ __decorateClass([
1512
+ Property({ name: "notes", type: "text", nullable: true })
1513
+ ], SalesReturn.prototype, "notes", 2);
1514
+ __decorateClass([
1515
+ Property({ name: "returned_at", type: Date, nullable: true })
1516
+ ], SalesReturn.prototype, "returnedAt", 2);
1517
+ __decorateClass([
1518
+ Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
1519
+ ], SalesReturn.prototype, "createdAt", 2);
1520
+ __decorateClass([
1521
+ Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
1522
+ ], SalesReturn.prototype, "updatedAt", 2);
1523
+ __decorateClass([
1524
+ Property({ name: "deleted_at", type: Date, nullable: true })
1525
+ ], SalesReturn.prototype, "deletedAt", 2);
1526
+ __decorateClass([
1527
+ OneToMany(() => SalesReturnLine, (line) => line.salesReturn)
1528
+ ], SalesReturn.prototype, "lines", 2);
1529
+ SalesReturn = __decorateClass([
1530
+ Entity({ tableName: "sales_returns" }),
1531
+ Index({ name: "sales_returns_scope_idx", properties: ["order", "organizationId", "tenantId"] }),
1532
+ Index({ name: "sales_returns_status_idx", properties: ["organizationId", "tenantId", "status"] }),
1533
+ Unique({ name: "sales_returns_number_unique", properties: ["organizationId", "tenantId", "returnNumber"] })
1534
+ ], SalesReturn);
1535
+ OptionalProps;
1536
+ let SalesReturnLine = class {
1537
+ constructor() {
1538
+ this.quantityReturned = "0";
1539
+ this.unitPriceNet = "0";
1540
+ this.unitPriceGross = "0";
1541
+ this.totalNetAmount = "0";
1542
+ this.totalGrossAmount = "0";
1543
+ this.createdAt = /* @__PURE__ */ new Date();
1544
+ this.updatedAt = /* @__PURE__ */ new Date();
1545
+ }
1546
+ };
1547
+ __decorateClass([
1548
+ PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
1549
+ ], SalesReturnLine.prototype, "id", 2);
1550
+ __decorateClass([
1551
+ ManyToOne(() => SalesReturn, { fieldName: "return_id" })
1552
+ ], SalesReturnLine.prototype, "salesReturn", 2);
1553
+ __decorateClass([
1554
+ ManyToOne(() => SalesOrderLine, { fieldName: "order_line_id" })
1555
+ ], SalesReturnLine.prototype, "orderLine", 2);
1556
+ __decorateClass([
1557
+ Property({ name: "organization_id", type: "uuid" })
1558
+ ], SalesReturnLine.prototype, "organizationId", 2);
1559
+ __decorateClass([
1560
+ Property({ name: "tenant_id", type: "uuid" })
1561
+ ], SalesReturnLine.prototype, "tenantId", 2);
1562
+ __decorateClass([
1563
+ Property({ name: "quantity_returned", type: "numeric", precision: 18, scale: 4, default: "0" })
1564
+ ], SalesReturnLine.prototype, "quantityReturned", 2);
1565
+ __decorateClass([
1566
+ Property({ name: "unit_price_net", type: "numeric", precision: 18, scale: 4, default: "0" })
1567
+ ], SalesReturnLine.prototype, "unitPriceNet", 2);
1568
+ __decorateClass([
1569
+ Property({ name: "unit_price_gross", type: "numeric", precision: 18, scale: 4, default: "0" })
1570
+ ], SalesReturnLine.prototype, "unitPriceGross", 2);
1571
+ __decorateClass([
1572
+ Property({ name: "total_net_amount", type: "numeric", precision: 18, scale: 4, default: "0" })
1573
+ ], SalesReturnLine.prototype, "totalNetAmount", 2);
1574
+ __decorateClass([
1575
+ Property({ name: "total_gross_amount", type: "numeric", precision: 18, scale: 4, default: "0" })
1576
+ ], SalesReturnLine.prototype, "totalGrossAmount", 2);
1577
+ __decorateClass([
1578
+ Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
1579
+ ], SalesReturnLine.prototype, "createdAt", 2);
1580
+ __decorateClass([
1581
+ Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
1582
+ ], SalesReturnLine.prototype, "updatedAt", 2);
1583
+ __decorateClass([
1584
+ Property({ name: "deleted_at", type: Date, nullable: true })
1585
+ ], SalesReturnLine.prototype, "deletedAt", 2);
1586
+ SalesReturnLine = __decorateClass([
1587
+ Entity({ tableName: "sales_return_lines" }),
1588
+ Index({ name: "sales_return_lines_return_idx", properties: ["salesReturn", "organizationId", "tenantId"] }),
1589
+ Index({ name: "sales_return_lines_order_line_idx", properties: ["orderLine", "organizationId", "tenantId"] })
1590
+ ], SalesReturnLine);
1479
1591
  let SalesInvoice = class {
1480
1592
  constructor() {
1481
1593
  this.subtotalNetAmount = "0";
@@ -2187,6 +2299,8 @@ export {
2187
2299
  SalesQuote,
2188
2300
  SalesQuoteAdjustment,
2189
2301
  SalesQuoteLine,
2302
+ SalesReturn,
2303
+ SalesReturnLine,
2190
2304
  SalesSettings,
2191
2305
  SalesShipment,
2192
2306
  SalesShipmentItem,