@aglyn/plugins-commerce 1.0.0-beta.220 → 1.0.0-beta.222

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 (130) hide show
  1. package/README.md +4 -2
  2. package/package.json +14 -13
  3. package/src/lib/components/console/catalog-organization-card.component.js +9 -0
  4. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  5. package/src/lib/components/console/discounts-card.component.js +8 -0
  6. package/src/lib/components/console/discounts-card.component.js.map +1 -1
  7. package/src/lib/components/console/gift-cards-card.component.js +8 -0
  8. package/src/lib/components/console/gift-cards-card.component.js.map +1 -1
  9. package/src/lib/components/console/host-coupons-card.component.js +8 -0
  10. package/src/lib/components/console/host-coupons-card.component.js.map +1 -1
  11. package/src/lib/components/console/host-orders-card.component.js +34 -70
  12. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  13. package/src/lib/components/console/product-zones.d.ts +7 -6
  14. package/src/lib/components/console/product-zones.js +5 -4
  15. package/src/lib/components/console/product-zones.js.map +1 -1
  16. package/src/lib/components/console/products-hub-card.component.js +86 -284
  17. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  18. package/src/lib/declarations.console-server.d.ts +38 -0
  19. package/src/lib/declarations.console-server.js +67 -0
  20. package/src/lib/declarations.console-server.js.map +1 -0
  21. package/src/lib/model/commerce-gift-cards.d.ts +26 -0
  22. package/src/lib/model/commerce-gift-cards.js +42 -0
  23. package/src/lib/model/commerce-gift-cards.js.map +1 -1
  24. package/src/lib/model/commerce-orders.d.ts +0 -57
  25. package/src/lib/model/commerce-orders.js +0 -80
  26. package/src/lib/model/commerce-orders.js.map +1 -1
  27. package/src/lib/model/index.d.ts +0 -1
  28. package/src/lib/model/index.js +0 -1
  29. package/src/lib/model/index.js.map +1 -1
  30. package/src/lib/plugin.js +5 -0
  31. package/src/lib/plugin.js.map +1 -1
  32. package/src/lib/server/api-v1/openapi.d.ts +27 -0
  33. package/src/lib/server/api-v1/openapi.js +219 -0
  34. package/src/lib/server/api-v1/openapi.js.map +1 -0
  35. package/src/lib/server/api-v1/orders-and-products.d.ts +19 -0
  36. package/src/lib/server/api-v1/orders-and-products.js +419 -0
  37. package/src/lib/server/api-v1/orders-and-products.js.map +1 -0
  38. package/src/lib/server/billing-webhook.js +83 -56
  39. package/src/lib/server/billing-webhook.js.map +1 -1
  40. package/src/lib/server/download.js +4 -1
  41. package/src/lib/server/download.js.map +1 -1
  42. package/src/lib/server/fulfill-order.d.ts +52 -11
  43. package/src/lib/server/fulfill-order.js +6 -9
  44. package/src/lib/server/fulfill-order.js.map +1 -1
  45. package/src/lib/server/gift-card-issue.d.ts +57 -0
  46. package/src/lib/server/gift-card-issue.js +155 -0
  47. package/src/lib/server/gift-card-issue.js.map +1 -0
  48. package/src/lib/server/gift-cards.js +25 -84
  49. package/src/lib/server/gift-cards.js.map +1 -1
  50. package/src/lib/server/membership-register.js +9 -8
  51. package/src/lib/server/membership-register.js.map +1 -1
  52. package/src/lib/server/newsletter.js +7 -5
  53. package/src/lib/server/newsletter.js.map +1 -1
  54. package/src/lib/server/paid-media-delivery.d.ts +21 -0
  55. package/src/lib/server/paid-media-delivery.js +23 -5
  56. package/src/lib/server/paid-media-delivery.js.map +1 -1
  57. package/src/lib/server/paid-media-serve-count.d.ts +28 -0
  58. package/src/lib/server/paid-media-serve-count.js +46 -0
  59. package/src/lib/server/paid-media-serve-count.js.map +1 -0
  60. package/src/lib/server/person-eraser.d.ts +45 -0
  61. package/src/lib/server/person-eraser.js +57 -0
  62. package/src/lib/server/person-eraser.js.map +1 -0
  63. package/src/lib/server/pos-order.js +17 -9
  64. package/src/lib/server/pos-order.js.map +1 -1
  65. package/src/lib/server/refund.js +15 -15
  66. package/src/lib/server/refund.js.map +1 -1
  67. package/src/lib/server/restock-flag.d.ts +2 -2
  68. package/src/lib/server/restock-flag.js +1 -1
  69. package/src/lib/server/restock-flag.js.map +1 -1
  70. package/src/lib/server/stream.js +4 -1
  71. package/src/lib/server/stream.js.map +1 -1
  72. package/src/lib/server.js +5 -21
  73. package/src/lib/server.js.map +1 -1
  74. package/src/lib/testing/stand-in-person-records.d.ts +43 -0
  75. package/src/lib/testing/stand-in-person-records.js +63 -0
  76. package/src/lib/testing/stand-in-person-records.js.map +1 -0
  77. package/src/lib/testing/stand-in-record-system.d.ts +11 -2
  78. package/src/lib/testing/stand-in-record-system.js +5 -3
  79. package/src/lib/testing/stand-in-record-system.js.map +1 -1
  80. package/src/lib/transfer/gift-card-confirm-step.component.d.ts +22 -0
  81. package/src/lib/transfer/gift-card-confirm-step.component.js +259 -0
  82. package/src/lib/transfer/gift-card-confirm-step.component.js.map +1 -0
  83. package/src/lib/transfer/gift-cards-plan.d.ts +29 -0
  84. package/src/lib/transfer/gift-cards-plan.js +40 -0
  85. package/src/lib/transfer/gift-cards-plan.js.map +1 -0
  86. package/src/lib/transfer/gift-cards.server.d.ts +34 -0
  87. package/src/lib/transfer/gift-cards.server.js +296 -0
  88. package/src/lib/transfer/gift-cards.server.js.map +1 -0
  89. package/src/lib/transfer/list-filter.d.ts +29 -0
  90. package/src/lib/transfer/list-filter.js +112 -0
  91. package/src/lib/transfer/list-filter.js.map +1 -0
  92. package/src/lib/transfer/product-import-results.d.ts +29 -0
  93. package/src/lib/transfer/product-import-results.js +49 -0
  94. package/src/lib/transfer/product-import-results.js.map +1 -0
  95. package/src/lib/transfer/product-import-step.component.d.ts +30 -0
  96. package/src/lib/transfer/product-import-step.component.js +99 -0
  97. package/src/lib/transfer/product-import-step.component.js.map +1 -0
  98. package/src/lib/transfer/product-transfer.d.ts +211 -0
  99. package/src/lib/transfer/product-transfer.js +1594 -0
  100. package/src/lib/transfer/product-transfer.js.map +1 -0
  101. package/src/lib/transfer/products.server.d.ts +44 -0
  102. package/src/lib/transfer/products.server.js +550 -0
  103. package/src/lib/transfer/products.server.js.map +1 -0
  104. package/src/lib/transfer/records-transfer.d.ts +182 -0
  105. package/src/lib/transfer/records-transfer.js +1153 -0
  106. package/src/lib/transfer/records-transfer.js.map +1 -0
  107. package/src/lib/transfer/records.server.d.ts +68 -0
  108. package/src/lib/transfer/records.server.js +455 -0
  109. package/src/lib/transfer/records.server.js.map +1 -0
  110. package/src/lib/transfer/register-transfer-resources.d.ts +17 -0
  111. package/src/lib/transfer/register-transfer-resources.js +171 -0
  112. package/src/lib/transfer/register-transfer-resources.js.map +1 -0
  113. package/src/lib/transfer/register-transfer-ui.d.ts +23 -0
  114. package/src/lib/transfer/register-transfer-ui.js +78 -0
  115. package/src/lib/transfer/register-transfer-ui.js.map +1 -0
  116. package/src/lib/transfer/server-common.d.ts +76 -0
  117. package/src/lib/transfer/server-common.js +165 -0
  118. package/src/lib/transfer/server-common.js.map +1 -0
  119. package/src/lib/transfer/transfer-header-actions.component.d.ts +39 -0
  120. package/src/lib/transfer/transfer-header-actions.component.js +79 -0
  121. package/src/lib/transfer/transfer-header-actions.component.js.map +1 -0
  122. package/src/lib/transfer/transfer-keys.d.ts +31 -0
  123. package/src/lib/transfer/transfer-keys.js +56 -0
  124. package/src/lib/transfer/transfer-keys.js.map +1 -0
  125. package/src/lib/model/commerce-io.d.ts +0 -36
  126. package/src/lib/model/commerce-io.js +0 -245
  127. package/src/lib/model/commerce-io.js.map +0 -1
  128. package/src/lib/server/contact-refund.d.ts +0 -117
  129. package/src/lib/server/contact-refund.js +0 -196
  130. package/src/lib/server/contact-refund.js.map +0 -1
@@ -0,0 +1,259 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ 'use client';
17
+ import { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
20
+ import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
21
+ import { useUser } from "@aglyn/tenant-feature-instance";
22
+ import { Alert, AlertTitle, Checkbox, Chip, FormControlLabel, Stack, TableBody, TableCell, TableHead, TablePagination, TableRow, TextField, Typography } from "@mui/material";
23
+ import { useEffect, useMemo, useState } from "react";
24
+ import { giftCardMoney, typedDollarsToCents } from "./records-transfer.js";
25
+ const PAGE = 25;
26
+ /** The plan route's largest page. */ const ROWS_PAGE = 200;
27
+ function readAnswer(value) {
28
+ var _answer_typed;
29
+ const answer = value && typeof value === 'object' ? value : {};
30
+ return {
31
+ typed: String((_answer_typed = answer.typed) != null ? _answer_typed : ''),
32
+ email: answer.email === true
33
+ };
34
+ }
35
+ export function GiftCardConfirmStep(props) {
36
+ const { orgId, jobId, value, setValue, setComplete } = props;
37
+ const { data: user } = useUser();
38
+ const answer = readAnswer(value);
39
+ const [cards, setCards] = useState(null);
40
+ const [error, setError] = useState(null);
41
+ const [page, setPage] = useState(0);
42
+ // Every card the dry run issues, page by page from the stored plan.
43
+ useEffect(()=>{
44
+ if (!user || !orgId || !jobId) return undefined;
45
+ let live = true;
46
+ void (async ()=>{
47
+ try {
48
+ const found = [];
49
+ let offset = 0;
50
+ while(offset !== null){
51
+ var _payload_error;
52
+ const response = await authorizedFetch(user, '/api/transfer/plan', {
53
+ method: 'POST',
54
+ headers: {
55
+ 'Content-Type': 'application/json'
56
+ },
57
+ body: JSON.stringify({
58
+ orgId,
59
+ jobId,
60
+ action: 'rows',
61
+ offset,
62
+ limit: ROWS_PAGE,
63
+ verdicts: [
64
+ 'create'
65
+ ]
66
+ })
67
+ });
68
+ const payload = await response.json().catch(()=>({}));
69
+ if (!response.ok || !payload.rows) throw new Error((_payload_error = payload.error) != null ? _payload_error : 'The cards could not be read.');
70
+ for (const row of payload.rows.rows){
71
+ const card = row.giftCard;
72
+ if (card && !card.problem) found.push(card);
73
+ }
74
+ offset = payload.rows.next;
75
+ }
76
+ if (live) setCards(found);
77
+ } catch (reason) {
78
+ if (live) setError(reason instanceof Error ? reason.message : 'The cards could not be read.');
79
+ }
80
+ })();
81
+ return ()=>{
82
+ live = false;
83
+ };
84
+ }, [
85
+ user,
86
+ orgId,
87
+ jobId
88
+ ]);
89
+ const totalCents = useMemo(()=>(cards != null ? cards : []).reduce((sum, card)=>sum + card.amountCents, 0), [
90
+ cards
91
+ ]);
92
+ const typedCents = typedDollarsToCents(answer.typed);
93
+ const matches = cards !== null && typedCents === totalCents;
94
+ useEffect(()=>{
95
+ // Nothing to issue needs no total: the review says why each row is held.
96
+ setComplete(cards !== null && (cards.length === 0 || matches));
97
+ }, [
98
+ cards,
99
+ matches,
100
+ setComplete
101
+ ]);
102
+ const save = (next)=>{
103
+ const merged = _extends({}, answer, next);
104
+ const cents = typedDollarsToCents(merged.typed);
105
+ setValue(_extends({
106
+ typed: merged.typed,
107
+ email: merged.email
108
+ }, cents !== null && cents > 0 ? {
109
+ totalCents: cents
110
+ } : {}));
111
+ };
112
+ if (error) return /*#__PURE__*/ _jsx(Alert, {
113
+ severity: "error",
114
+ children: error
115
+ });
116
+ if (cards === null) {
117
+ return /*#__PURE__*/ _jsx(Typography, {
118
+ variant: "body2",
119
+ color: "text.secondary",
120
+ children: 'Reading the cards this import issues…'
121
+ });
122
+ }
123
+ if (!cards.length) {
124
+ return /*#__PURE__*/ _jsx(Alert, {
125
+ severity: "info",
126
+ children: 'No card in this file can be issued. The review lists every row with the reason.'
127
+ });
128
+ }
129
+ const madeCodes = cards.filter((card)=>card.newCode || card.madeCode).length;
130
+ const shown = cards.slice(page * PAGE, page * PAGE + PAGE);
131
+ return /*#__PURE__*/ _jsxs(Stack, {
132
+ spacing: 2,
133
+ children: [
134
+ /*#__PURE__*/ _jsxs(Alert, {
135
+ severity: "warning",
136
+ children: [
137
+ /*#__PURE__*/ _jsx(AlertTitle, {
138
+ children: `${cards.length.toLocaleString('en-US')} gift card${cards.length === 1 ? '' : 's'} worth ${giftCardMoney(totalCents)}`
139
+ }),
140
+ 'Each card is spendable money the moment it is issued. Check every code and value, then type the total ' + 'to issue them.'
141
+ ]
142
+ }),
143
+ /*#__PURE__*/ _jsxs(ScrollTable, {
144
+ size: "small",
145
+ "aria-label": "Gift cards this import issues",
146
+ children: [
147
+ /*#__PURE__*/ _jsx(TableHead, {
148
+ children: /*#__PURE__*/ _jsxs(TableRow, {
149
+ children: [
150
+ /*#__PURE__*/ _jsx(TableCell, {
151
+ children: "Code"
152
+ }),
153
+ /*#__PURE__*/ _jsx(TableCell, {
154
+ align: "right",
155
+ children: "Value"
156
+ }),
157
+ /*#__PURE__*/ _jsx(TableCell, {
158
+ children: "Recipient"
159
+ }),
160
+ /*#__PURE__*/ _jsx(TableCell, {
161
+ children: "Note"
162
+ })
163
+ ]
164
+ })
165
+ }),
166
+ /*#__PURE__*/ _jsx(TableBody, {
167
+ children: shown.map((card)=>{
168
+ var _card_recipientEmail, _card_note;
169
+ return /*#__PURE__*/ _jsxs(TableRow, {
170
+ children: [
171
+ /*#__PURE__*/ _jsx(TableCell, {
172
+ children: /*#__PURE__*/ _jsxs(Stack, {
173
+ direction: "row",
174
+ spacing: 1,
175
+ sx: {
176
+ alignItems: 'center'
177
+ },
178
+ children: [
179
+ /*#__PURE__*/ _jsx(Typography, {
180
+ variant: "body2",
181
+ sx: {
182
+ fontFamily: 'monospace'
183
+ },
184
+ children: card.code
185
+ }),
186
+ card.newCode ? /*#__PURE__*/ _jsx(Chip, {
187
+ size: "small",
188
+ label: "New code: the file's was taken"
189
+ }) : null,
190
+ card.madeCode ? /*#__PURE__*/ _jsx(Chip, {
191
+ size: "small",
192
+ label: "New code"
193
+ }) : null
194
+ ]
195
+ })
196
+ }),
197
+ /*#__PURE__*/ _jsx(TableCell, {
198
+ align: "right",
199
+ children: giftCardMoney(card.amountCents)
200
+ }),
201
+ /*#__PURE__*/ _jsx(TableCell, {
202
+ children: (_card_recipientEmail = card.recipientEmail) != null ? _card_recipientEmail : '—'
203
+ }),
204
+ /*#__PURE__*/ _jsx(TableCell, {
205
+ children: (_card_note = card.note) != null ? _card_note : '—'
206
+ })
207
+ ]
208
+ }, card.code);
209
+ })
210
+ })
211
+ ]
212
+ }),
213
+ cards.length > PAGE ? /*#__PURE__*/ _jsx(TablePagination, {
214
+ component: "div",
215
+ count: cards.length,
216
+ page: page,
217
+ onPageChange: (_event, next)=>setPage(next),
218
+ rowsPerPage: PAGE,
219
+ rowsPerPageOptions: [
220
+ PAGE
221
+ ]
222
+ }) : null,
223
+ /*#__PURE__*/ _jsx(TextField, {
224
+ label: "Type the total value to issue these cards",
225
+ value: answer.typed,
226
+ onChange: (event)=>save({
227
+ typed: event.target.value
228
+ }),
229
+ error: Boolean(answer.typed) && !matches,
230
+ helperText: answer.typed && !matches ? `That is not the total. These cards add up to ${giftCardMoney(totalCents)}.` : `Type ${giftCardMoney(totalCents)}.`,
231
+ autoComplete: "off",
232
+ slotProps: {
233
+ htmlInput: {
234
+ inputMode: 'decimal'
235
+ }
236
+ }
237
+ }),
238
+ /*#__PURE__*/ _jsx(FormControlLabel, {
239
+ control: /*#__PURE__*/ _jsx(Checkbox, {
240
+ checked: answer.email,
241
+ onChange: (event)=>save({
242
+ email: event.target.checked
243
+ })
244
+ }),
245
+ label: /*#__PURE__*/ _jsxs(Typography, {
246
+ variant: "body2",
247
+ children: [
248
+ 'Email each recipient their code as the card is issued.',
249
+ madeCodes ? ` ${madeCodes.toLocaleString('en-US')} card${madeCodes === 1 ? ' has' : 's have'} a new code nobody holds yet: email them, or share the codes yourself.` : ' Leave this off when the shoppers already hold these codes.'
250
+ ]
251
+ })
252
+ })
253
+ ]
254
+ });
255
+ }
256
+ GiftCardConfirmStep.displayName = 'GiftCardConfirmStep';
257
+ export default GiftCardConfirmStep;
258
+
259
+ //# sourceMappingURL=gift-card-confirm-step.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/transfer/gift-card-confirm-step.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport type { PlannedTransferRow, TransferPlanRowsResponse } from '@aglyn/aglyn/data-transfer'\nimport type { TransferWizardStepProps } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n AlertTitle,\n Checkbox,\n Chip,\n FormControlLabel,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TablePagination,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useEffect, useMemo, useState } from 'react'\nimport { giftCardMoney, typedDollarsToCents, type GiftCardPlannedRow, type GiftCardRowPlan } from './records-transfer'\n\n/**\n * THE GIFT CARD IMPORT'S CONFIRM STEP (AGL-3551), after Conflicts: every\n * card the dry run will issue, with its code and value, and the total typed\n * back. The step is complete only when the typed total is exactly the total\n * of the cards listed; the server reads the same answer from `extras` and\n * issues nothing unless it is the total it counted itself.\n *\n * The answer also says whether each recipient is emailed their code. It is\n * off by default: cards moved from another platform carry codes shoppers\n * already hold.\n */\n\n/** The step's answer, as it rides in `extras`. */\ninterface ConfirmAnswer {\n typed: string\n totalCents?: number\n email: boolean\n}\n\nconst PAGE = 25\n/** The plan route's largest page. */\nconst ROWS_PAGE = 200\n\nfunction readAnswer(value: unknown): ConfirmAnswer {\n const answer = (value && typeof value === 'object' ? value : {}) as Partial<ConfirmAnswer>\n return { typed: String(answer.typed ?? ''), email: answer.email === true }\n}\n\nexport function GiftCardConfirmStep(props: TransferWizardStepProps) {\n const { orgId, jobId, value, setValue, setComplete } = props\n const { data: user } = useUser()\n const answer = readAnswer(value)\n const [cards, setCards] = useState<GiftCardRowPlan[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [page, setPage] = useState(0)\n\n // Every card the dry run issues, page by page from the stored plan.\n useEffect(() => {\n if (!user || !orgId || !jobId) return undefined\n let live = true\n void (async () => {\n try {\n const found: GiftCardRowPlan[] = []\n let offset: number | null = 0\n while (offset !== null) {\n const response = await authorizedFetch(user, '/api/transfer/plan', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ orgId, jobId, action: 'rows', offset, limit: ROWS_PAGE, verdicts: ['create'] }),\n })\n const payload = (await response.json().catch(() => ({}))) as Partial<TransferPlanRowsResponse> & { error?: string }\n if (!response.ok || !payload.rows) throw new Error(payload.error ?? 'The cards could not be read.')\n for (const row of payload.rows.rows as PlannedTransferRow[]) {\n const card = (row as GiftCardPlannedRow).giftCard\n if (card && !card.problem) found.push(card)\n }\n offset = payload.rows.next\n }\n if (live) setCards(found)\n } catch (reason) {\n if (live) setError(reason instanceof Error ? reason.message : 'The cards could not be read.')\n }\n })()\n return () => {\n live = false\n }\n }, [user, orgId, jobId])\n\n const totalCents = useMemo(() => (cards ?? []).reduce((sum, card) => sum + card.amountCents, 0), [cards])\n const typedCents = typedDollarsToCents(answer.typed)\n const matches = cards !== null && typedCents === totalCents\n\n useEffect(() => {\n // Nothing to issue needs no total: the review says why each row is held.\n setComplete(cards !== null && (cards.length === 0 || matches))\n }, [cards, matches, setComplete])\n\n const save = (next: Partial<ConfirmAnswer>) => {\n const merged = { ...answer, ...next }\n const cents = typedDollarsToCents(merged.typed)\n setValue({ typed: merged.typed, email: merged.email, ...(cents !== null && cents > 0 ? { totalCents: cents } : {}) })\n }\n\n if (error) return <Alert severity=\"error\">{error}</Alert>\n if (cards === null) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Reading the cards this import issues…'}\n </Typography>\n )\n }\n if (!cards.length) {\n return (\n <Alert severity=\"info\">\n {'No card in this file can be issued. The review lists every row with the reason.'}\n </Alert>\n )\n }\n\n const madeCodes = cards.filter((card) => card.newCode || card.madeCode).length\n const shown = cards.slice(page * PAGE, page * PAGE + PAGE)\n return (\n <Stack spacing={2}>\n <Alert severity=\"warning\">\n <AlertTitle>\n {`${cards.length.toLocaleString('en-US')} gift card${cards.length === 1 ? '' : 's'} worth ${giftCardMoney(totalCents)}`}\n </AlertTitle>\n {'Each card is spendable money the moment it is issued. Check every code and value, then type the total ' +\n 'to issue them.'}\n </Alert>\n <ScrollTable size=\"small\" aria-label=\"Gift cards this import issues\">\n <TableHead>\n <TableRow>\n <TableCell>Code</TableCell>\n <TableCell align=\"right\">Value</TableCell>\n <TableCell>Recipient</TableCell>\n <TableCell>Note</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {shown.map((card) => (\n <TableRow key={card.code}>\n <TableCell>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography variant=\"body2\" sx={{ fontFamily: 'monospace' }}>\n {card.code}\n </Typography>\n {card.newCode ? <Chip size=\"small\" label=\"New code: the file's was taken\" /> : null}\n {card.madeCode ? <Chip size=\"small\" label=\"New code\" /> : null}\n </Stack>\n </TableCell>\n <TableCell align=\"right\">{giftCardMoney(card.amountCents)}</TableCell>\n <TableCell>{card.recipientEmail ?? '—'}</TableCell>\n <TableCell>{card.note ?? '—'}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n {cards.length > PAGE ? (\n <TablePagination\n component=\"div\"\n count={cards.length}\n page={page}\n onPageChange={(_event, next) => setPage(next)}\n rowsPerPage={PAGE}\n rowsPerPageOptions={[PAGE]}\n />\n ) : null}\n <TextField\n label=\"Type the total value to issue these cards\"\n value={answer.typed}\n onChange={(event) => save({ typed: event.target.value })}\n error={Boolean(answer.typed) && !matches}\n helperText={\n answer.typed && !matches\n ? `That is not the total. These cards add up to ${giftCardMoney(totalCents)}.`\n : `Type ${giftCardMoney(totalCents)}.`\n }\n autoComplete=\"off\"\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <FormControlLabel\n control={<Checkbox checked={answer.email} onChange={(event) => save({ email: event.target.checked })} />}\n label={\n <Typography variant=\"body2\">\n {'Email each recipient their code as the card is issued.'}\n {madeCodes\n ? ` ${madeCodes.toLocaleString('en-US')} card${madeCodes === 1 ? ' has' : 's have'} a new code nobody holds yet: email them, or share the codes yourself.`\n : ' Leave this off when the shoppers already hold these codes.'}\n </Typography>\n }\n />\n </Stack>\n )\n}\nGiftCardConfirmStep.displayName = 'GiftCardConfirmStep'\n\nexport default GiftCardConfirmStep\n"],"names":["ScrollTable","authorizedFetch","useUser","Alert","AlertTitle","Checkbox","Chip","FormControlLabel","Stack","TableBody","TableCell","TableHead","TablePagination","TableRow","TextField","Typography","useEffect","useMemo","useState","giftCardMoney","typedDollarsToCents","PAGE","ROWS_PAGE","readAnswer","value","answer","typed","String","email","GiftCardConfirmStep","props","orgId","jobId","setValue","setComplete","data","user","cards","setCards","error","setError","page","setPage","undefined","live","found","offset","payload","response","method","headers","body","JSON","stringify","action","limit","verdicts","json","catch","ok","rows","Error","row","card","giftCard","problem","push","next","reason","message","totalCents","reduce","sum","amountCents","typedCents","matches","length","save","merged","cents","severity","variant","color","madeCodes","filter","newCode","madeCode","shown","slice","spacing","toLocaleString","size","aria-label","align","map","direction","sx","alignItems","fontFamily","code","label","recipientEmail","note","component","count","onPageChange","_event","rowsPerPage","rowsPerPageOptions","onChange","event","target","Boolean","helperText","autoComplete","slotProps","htmlInput","inputMode","control","checked","displayName"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { TransferPlanRefusal } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources';
18
+ /**
19
+ * The refusal for importing gift cards on a plan without them (AGL-3548),
20
+ * or `null` when the plan has them: the sentence the Gift cards card's issue
21
+ * route answers (`server/gift-cards.ts`), naming the plan that includes
22
+ * them, in the 403 `plan_required` body every transfer route answers a plan
23
+ * with. The `commerce.gift-cards` declaration gates imports only — the cards
24
+ * a workspace holds are listed, and exported, on every plan. Asked by the
25
+ * transfer gate (the resource's `planGate`) and again by each hook that
26
+ * issues or voids a card, so the sweep that resumes an import is refused
27
+ * alike.
28
+ */
29
+ export declare function giftCardsPlanRefusal(org: unknown): TransferPlanRefusal | null;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { checkEntitlement, planLabelGrantingFeature } from "@aglyn/aglyn/app-utils/plan-entitlements";
17
+ /**
18
+ * The refusal for importing gift cards on a plan without them (AGL-3548),
19
+ * or `null` when the plan has them: the sentence the Gift cards card's issue
20
+ * route answers (`server/gift-cards.ts`), naming the plan that includes
21
+ * them, in the 403 `plan_required` body every transfer route answers a plan
22
+ * with. The `commerce.gift-cards` declaration gates imports only — the cards
23
+ * a workspace holds are listed, and exported, on every plan. Asked by the
24
+ * transfer gate (the resource's `planGate`) and again by each hook that
25
+ * issues or voids a card, so the sweep that resumes an import is refused
26
+ * alike.
27
+ */ export function giftCardsPlanRefusal(org) {
28
+ if (checkEntitlement(org, 'giftCards')) return null;
29
+ const plan = planLabelGrantingFeature('giftCards');
30
+ return {
31
+ status: 403,
32
+ body: {
33
+ error: 'Gift cards are not included on this plan.' + (plan ? ` Included from ${plan}.` : ''),
34
+ reason: 'plan_required',
35
+ code: 'giftCards'
36
+ }
37
+ };
38
+ }
39
+
40
+ //# sourceMappingURL=gift-cards-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/transfer/gift-cards-plan.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { checkEntitlement, planLabelGrantingFeature } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport type { TransferPlanRefusal } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\n\n/**\n * The refusal for importing gift cards on a plan without them (AGL-3548),\n * or `null` when the plan has them: the sentence the Gift cards card's issue\n * route answers (`server/gift-cards.ts`), naming the plan that includes\n * them, in the 403 `plan_required` body every transfer route answers a plan\n * with. The `commerce.gift-cards` declaration gates imports only — the cards\n * a workspace holds are listed, and exported, on every plan. Asked by the\n * transfer gate (the resource's `planGate`) and again by each hook that\n * issues or voids a card, so the sweep that resumes an import is refused\n * alike.\n */\nexport function giftCardsPlanRefusal(org: unknown): TransferPlanRefusal | null {\n if (checkEntitlement(org as never, 'giftCards')) return null\n const plan = planLabelGrantingFeature('giftCards')\n return {\n status: 403,\n body: {\n error: 'Gift cards are not included on this plan.' + (plan ? ` Included from ${plan}.` : ''),\n reason: 'plan_required',\n code: 'giftCards',\n },\n }\n}\n"],"names":["checkEntitlement","planLabelGrantingFeature","giftCardsPlanRefusal","org","plan","status","body","error","reason","code"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,gBAAgB,EAAEC,wBAAwB,QAAQ,2CAA0C;AAGrG;;;;;;;;;;CAUC,GACD,OAAO,SAASC,qBAAqBC,GAAY;IAC/C,IAAIH,iBAAiBG,KAAc,cAAc,OAAO;IACxD,MAAMC,OAAOH,yBAAyB;IACtC,OAAO;QACLI,QAAQ;QACRC,MAAM;YACJC,OAAO,8CAA+CH,CAAAA,OAAO,CAAC,eAAe,EAAEA,KAAK,CAAC,CAAC,GAAG,EAAC;YAC1FI,QAAQ;YACRC,MAAM;QACR;IACF;AACF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type BuildTransferPlanInput, type TransferChunk, type PlannedTransferRow, type TransferPlan, type TransferUndoSnapshot } from '@aglyn/aglyn/data-transfer';
18
+ import type { PluginTransferResource, TransferApplyResult, TransferApplyWriter, TransferResourceContext, TransferRevertResult } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources';
19
+ /**
20
+ * The dry run: the core's plan with a Balance required of every card, made
21
+ * into the cards it issues. The codes the file names are read once, so a
22
+ * code another card holds — however the file spaced or cased it — is never
23
+ * planned as a new card.
24
+ */
25
+ export declare function planGiftCards(ctx: TransferResourceContext, input: BuildTransferPlanInput): Promise<TransferPlan>;
26
+ /** Issues one chunk's cards, each through the Gift cards card's own issue path. */
27
+ export declare function applyGiftCards(ctx: TransferResourceContext, chunk: TransferChunk<PlannedTransferRow>, writer: TransferApplyWriter): Promise<TransferApplyResult>;
28
+ /**
29
+ * Undoes one chunk: each card voided — zeroed, never deleted — when nobody
30
+ * has spent from it; a spent or held card is a conflict that stays as it is,
31
+ * whatever the person decided, because a shopper holds that money.
32
+ */
33
+ export declare function revertGiftCards(ctx: TransferResourceContext, snapshot: TransferUndoSnapshot): Promise<TransferRevertResult>;
34
+ export declare const giftCardsTransfer: PluginTransferResource;