@porulle/core 0.6.0 → 0.8.0

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 (301) hide show
  1. package/dist/auth/setup.d.ts.map +1 -1
  2. package/dist/auth/setup.js +1 -0
  3. package/dist/config/defaults.d.ts.map +1 -1
  4. package/dist/config/defaults.js +5 -0
  5. package/dist/config/types.d.ts +17 -1
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/generated/plugin-manifest.d.ts +3 -0
  8. package/dist/generated/plugin-manifest.d.ts.map +1 -1
  9. package/dist/generated/plugin-manifest.js +1 -0
  10. package/dist/hooks/checkout.d.ts.map +1 -1
  11. package/dist/hooks/checkout.js +16 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/interfaces/rest/index.d.ts.map +1 -1
  16. package/dist/interfaces/rest/index.js +12 -0
  17. package/dist/interfaces/rest/routes/admin/staff.d.ts +12 -0
  18. package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -0
  19. package/dist/interfaces/rest/routes/admin/staff.js +172 -0
  20. package/dist/interfaces/rest/routes/analytics.d.ts +5 -0
  21. package/dist/interfaces/rest/routes/analytics.d.ts.map +1 -0
  22. package/dist/interfaces/rest/routes/analytics.js +24 -0
  23. package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
  24. package/dist/interfaces/rest/routes/carts.js +39 -2
  25. package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
  26. package/dist/interfaces/rest/routes/catalog.js +17 -1
  27. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  28. package/dist/interfaces/rest/routes/checkout.js +17 -0
  29. package/dist/interfaces/rest/routes/documents.d.ts +10 -0
  30. package/dist/interfaces/rest/routes/documents.d.ts.map +1 -0
  31. package/dist/interfaces/rest/routes/documents.js +40 -0
  32. package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
  33. package/dist/interfaces/rest/routes/orders.js +122 -1
  34. package/dist/interfaces/rest/routes/pricing.d.ts.map +1 -1
  35. package/dist/interfaces/rest/routes/pricing.js +36 -1
  36. package/dist/interfaces/rest/routes/settings.d.ts +5 -0
  37. package/dist/interfaces/rest/routes/settings.d.ts.map +1 -0
  38. package/dist/interfaces/rest/routes/settings.js +50 -0
  39. package/dist/interfaces/rest/routes/shipping.d.ts +5 -0
  40. package/dist/interfaces/rest/routes/shipping.d.ts.map +1 -0
  41. package/dist/interfaces/rest/routes/shipping.js +68 -0
  42. package/dist/interfaces/rest/routes/tax.d.ts +5 -0
  43. package/dist/interfaces/rest/routes/tax.d.ts.map +1 -0
  44. package/dist/interfaces/rest/routes/tax.js +68 -0
  45. package/dist/interfaces/rest/schemas/admin-staff.d.ts +899 -0
  46. package/dist/interfaces/rest/schemas/admin-staff.d.ts.map +1 -0
  47. package/dist/interfaces/rest/schemas/admin-staff.js +98 -0
  48. package/dist/interfaces/rest/schemas/analytics.d.ts +252 -0
  49. package/dist/interfaces/rest/schemas/analytics.d.ts.map +1 -0
  50. package/dist/interfaces/rest/schemas/analytics.js +33 -0
  51. package/dist/interfaces/rest/schemas/carts.d.ts +656 -0
  52. package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
  53. package/dist/interfaces/rest/schemas/carts.js +38 -0
  54. package/dist/interfaces/rest/schemas/catalog.d.ts +1230 -2
  55. package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
  56. package/dist/interfaces/rest/schemas/catalog.js +48 -0
  57. package/dist/interfaces/rest/schemas/checkout.d.ts +2 -0
  58. package/dist/interfaces/rest/schemas/checkout.d.ts.map +1 -1
  59. package/dist/interfaces/rest/schemas/checkout.js +4 -0
  60. package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
  61. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
  62. package/dist/interfaces/rest/schemas/documents.d.ts +509 -0
  63. package/dist/interfaces/rest/schemas/documents.d.ts.map +1 -0
  64. package/dist/interfaces/rest/schemas/documents.js +65 -0
  65. package/dist/interfaces/rest/schemas/orders.d.ts +4467 -7
  66. package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
  67. package/dist/interfaces/rest/schemas/orders.js +330 -0
  68. package/dist/interfaces/rest/schemas/pricing.d.ts +405 -0
  69. package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
  70. package/dist/interfaces/rest/schemas/pricing.js +70 -0
  71. package/dist/interfaces/rest/schemas/responses.d.ts +156 -0
  72. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  73. package/dist/interfaces/rest/schemas/search.d.ts +17 -0
  74. package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
  75. package/dist/interfaces/rest/schemas/settings.d.ts +397 -0
  76. package/dist/interfaces/rest/schemas/settings.d.ts.map +1 -0
  77. package/dist/interfaces/rest/schemas/settings.js +79 -0
  78. package/dist/interfaces/rest/schemas/shipping.d.ts +1093 -0
  79. package/dist/interfaces/rest/schemas/shipping.d.ts.map +1 -0
  80. package/dist/interfaces/rest/schemas/shipping.js +146 -0
  81. package/dist/interfaces/rest/schemas/tax.d.ts +1074 -0
  82. package/dist/interfaces/rest/schemas/tax.d.ts.map +1 -0
  83. package/dist/interfaces/rest/schemas/tax.js +132 -0
  84. package/dist/kernel/database/schema.d.ts +4 -0
  85. package/dist/kernel/database/schema.d.ts.map +1 -1
  86. package/dist/kernel/database/schema.js +8 -0
  87. package/dist/kernel/error-mapper.d.ts.map +1 -1
  88. package/dist/kernel/error-mapper.js +1 -0
  89. package/dist/kernel/errors.d.ts +5 -0
  90. package/dist/kernel/errors.d.ts.map +1 -1
  91. package/dist/kernel/errors.js +9 -0
  92. package/dist/kernel/hooks/types.d.ts +1 -1
  93. package/dist/kernel/hooks/types.d.ts.map +1 -1
  94. package/dist/kernel/plugin/manifest.d.ts +23 -0
  95. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  96. package/dist/kernel/plugin/manifest.js +17 -2
  97. package/dist/modules/analytics/module.d.ts.map +1 -1
  98. package/dist/modules/analytics/module.js +6 -0
  99. package/dist/modules/analytics/reports.d.ts +58 -0
  100. package/dist/modules/analytics/reports.d.ts.map +1 -0
  101. package/dist/modules/analytics/reports.js +249 -0
  102. package/dist/modules/analytics/service.d.ts +10 -0
  103. package/dist/modules/analytics/service.d.ts.map +1 -1
  104. package/dist/modules/analytics/service.js +14 -0
  105. package/dist/modules/cart/repository/index.d.ts +7 -0
  106. package/dist/modules/cart/repository/index.d.ts.map +1 -1
  107. package/dist/modules/cart/repository/index.js +25 -1
  108. package/dist/modules/cart/schema.d.ts +17 -0
  109. package/dist/modules/cart/schema.d.ts.map +1 -1
  110. package/dist/modules/cart/schema.js +2 -0
  111. package/dist/modules/cart/schemas.d.ts +1 -0
  112. package/dist/modules/cart/schemas.d.ts.map +1 -1
  113. package/dist/modules/cart/schemas.js +1 -0
  114. package/dist/modules/cart/service.d.ts +32 -0
  115. package/dist/modules/cart/service.d.ts.map +1 -1
  116. package/dist/modules/cart/service.js +58 -0
  117. package/dist/modules/catalog/entity-service.d.ts +21 -0
  118. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  119. package/dist/modules/catalog/entity-service.js +151 -6
  120. package/dist/modules/catalog/schema.d.ts +34 -0
  121. package/dist/modules/catalog/schema.d.ts.map +1 -1
  122. package/dist/modules/catalog/schema.js +5 -0
  123. package/dist/modules/catalog/schemas.d.ts +15 -1
  124. package/dist/modules/catalog/schemas.d.ts.map +1 -1
  125. package/dist/modules/catalog/schemas.js +17 -1
  126. package/dist/modules/catalog/service.d.ts +43 -1
  127. package/dist/modules/catalog/service.d.ts.map +1 -1
  128. package/dist/modules/catalog/service.js +6 -0
  129. package/dist/modules/documents/module.d.ts +7 -0
  130. package/dist/modules/documents/module.d.ts.map +1 -0
  131. package/dist/modules/documents/module.js +12 -0
  132. package/dist/modules/documents/pdf.d.ts +25 -0
  133. package/dist/modules/documents/pdf.d.ts.map +1 -0
  134. package/dist/modules/documents/pdf.js +80 -0
  135. package/dist/modules/documents/render.d.ts +32 -0
  136. package/dist/modules/documents/render.d.ts.map +1 -0
  137. package/dist/modules/documents/render.js +190 -0
  138. package/dist/modules/documents/repository/index.d.ts +25 -0
  139. package/dist/modules/documents/repository/index.d.ts.map +1 -0
  140. package/dist/modules/documents/repository/index.js +47 -0
  141. package/dist/modules/documents/schema.d.ts +214 -0
  142. package/dist/modules/documents/schema.d.ts.map +1 -0
  143. package/dist/modules/documents/schema.js +42 -0
  144. package/dist/modules/documents/service.d.ts +51 -0
  145. package/dist/modules/documents/service.d.ts.map +1 -0
  146. package/dist/modules/documents/service.js +119 -0
  147. package/dist/modules/fulfillment/service.d.ts +18 -0
  148. package/dist/modules/fulfillment/service.d.ts.map +1 -1
  149. package/dist/modules/fulfillment/service.js +85 -1
  150. package/dist/modules/media/service.d.ts +18 -0
  151. package/dist/modules/media/service.d.ts.map +1 -1
  152. package/dist/modules/media/service.js +26 -0
  153. package/dist/modules/orders/repository/index.d.ts +18 -1
  154. package/dist/modules/orders/repository/index.d.ts.map +1 -1
  155. package/dist/modules/orders/repository/index.js +86 -1
  156. package/dist/modules/orders/schema.d.ts +374 -0
  157. package/dist/modules/orders/schema.d.ts.map +1 -1
  158. package/dist/modules/orders/schema.js +52 -1
  159. package/dist/modules/orders/service.d.ts +102 -2
  160. package/dist/modules/orders/service.d.ts.map +1 -1
  161. package/dist/modules/orders/service.js +494 -23
  162. package/dist/modules/pricing/repository/index.d.ts +5 -0
  163. package/dist/modules/pricing/repository/index.d.ts.map +1 -1
  164. package/dist/modules/pricing/repository/index.js +19 -0
  165. package/dist/modules/pricing/service.d.ts +18 -0
  166. package/dist/modules/pricing/service.d.ts.map +1 -1
  167. package/dist/modules/pricing/service.js +57 -1
  168. package/dist/modules/settings/module.d.ts +6 -0
  169. package/dist/modules/settings/module.d.ts.map +1 -0
  170. package/dist/modules/settings/module.js +11 -0
  171. package/dist/modules/settings/repository/index.d.ts +16 -0
  172. package/dist/modules/settings/repository/index.d.ts.map +1 -0
  173. package/dist/modules/settings/repository/index.js +41 -0
  174. package/dist/modules/settings/schema.d.ts +121 -0
  175. package/dist/modules/settings/schema.d.ts.map +1 -0
  176. package/dist/modules/settings/schema.js +24 -0
  177. package/dist/modules/settings/service.d.ts +26 -0
  178. package/dist/modules/settings/service.d.ts.map +1 -0
  179. package/dist/modules/settings/service.js +51 -0
  180. package/dist/modules/shipping/calculator.d.ts +5 -0
  181. package/dist/modules/shipping/calculator.d.ts.map +1 -1
  182. package/dist/modules/shipping/calculator.js +10 -0
  183. package/dist/modules/shipping/module.d.ts +5 -1
  184. package/dist/modules/shipping/module.d.ts.map +1 -1
  185. package/dist/modules/shipping/module.js +4 -1
  186. package/dist/modules/shipping/repository/index.d.ts +27 -2
  187. package/dist/modules/shipping/repository/index.d.ts.map +1 -1
  188. package/dist/modules/shipping/repository/index.js +105 -1
  189. package/dist/modules/shipping/schema.d.ts +419 -0
  190. package/dist/modules/shipping/schema.d.ts.map +1 -0
  191. package/dist/modules/shipping/schema.js +56 -0
  192. package/dist/modules/shipping/service.d.ts +54 -0
  193. package/dist/modules/shipping/service.d.ts.map +1 -1
  194. package/dist/modules/shipping/service.js +161 -2
  195. package/dist/modules/tax/adapter.d.ts +13 -0
  196. package/dist/modules/tax/adapter.d.ts.map +1 -1
  197. package/dist/modules/tax/module.d.ts +5 -1
  198. package/dist/modules/tax/module.d.ts.map +1 -1
  199. package/dist/modules/tax/module.js +4 -1
  200. package/dist/modules/tax/repository/index.d.ts +38 -2
  201. package/dist/modules/tax/repository/index.d.ts.map +1 -1
  202. package/dist/modules/tax/repository/index.js +138 -1
  203. package/dist/modules/tax/schema.d.ts +355 -0
  204. package/dist/modules/tax/schema.d.ts.map +1 -0
  205. package/dist/modules/tax/schema.js +55 -0
  206. package/dist/modules/tax/service.d.ts +60 -1
  207. package/dist/modules/tax/service.d.ts.map +1 -1
  208. package/dist/modules/tax/service.js +227 -2
  209. package/dist/runtime/kernel-modules.d.ts +15 -2
  210. package/dist/runtime/kernel-modules.d.ts.map +1 -1
  211. package/dist/runtime/kernel-modules.js +4 -0
  212. package/dist/runtime/kernel-types.d.ts +5 -1
  213. package/dist/runtime/kernel-types.d.ts.map +1 -1
  214. package/dist/runtime/kernel-types.js +2 -0
  215. package/dist/runtime/server.d.ts.map +1 -1
  216. package/dist/runtime/server.js +35 -3
  217. package/dist/test-utils/create-plugin-test-app.d.ts +3 -0
  218. package/dist/test-utils/create-plugin-test-app.d.ts.map +1 -1
  219. package/dist/test-utils/create-plugin-test-app.js +15 -3
  220. package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
  221. package/dist/test-utils/rest-api-test-utils.js +6 -0
  222. package/package.json +3 -3
  223. package/src/auth/setup.ts +1 -0
  224. package/src/config/defaults.ts +5 -0
  225. package/src/config/types.ts +17 -1
  226. package/src/generated/plugin-capabilities.d.ts +1 -0
  227. package/src/generated/plugin-manifest.ts +1 -0
  228. package/src/generated/plugin-repositories.d.ts +1 -0
  229. package/src/hooks/checkout.ts +25 -3
  230. package/src/index.ts +1 -0
  231. package/src/interfaces/rest/index.ts +12 -0
  232. package/src/interfaces/rest/routes/admin/staff.ts +218 -0
  233. package/src/interfaces/rest/routes/analytics.ts +33 -0
  234. package/src/interfaces/rest/routes/carts.ts +52 -2
  235. package/src/interfaces/rest/routes/catalog.ts +34 -0
  236. package/src/interfaces/rest/routes/checkout.ts +22 -0
  237. package/src/interfaces/rest/routes/documents.ts +61 -0
  238. package/src/interfaces/rest/routes/orders.ts +172 -1
  239. package/src/interfaces/rest/routes/pricing.ts +44 -1
  240. package/src/interfaces/rest/routes/settings.ts +61 -0
  241. package/src/interfaces/rest/routes/shipping.ts +92 -0
  242. package/src/interfaces/rest/routes/tax.ts +90 -0
  243. package/src/interfaces/rest/schemas/admin-staff.ts +110 -0
  244. package/src/interfaces/rest/schemas/analytics.ts +39 -0
  245. package/src/interfaces/rest/schemas/carts.ts +40 -0
  246. package/src/interfaces/rest/schemas/catalog.ts +53 -0
  247. package/src/interfaces/rest/schemas/checkout.ts +4 -0
  248. package/src/interfaces/rest/schemas/documents.ts +72 -0
  249. package/src/interfaces/rest/schemas/orders.ts +361 -0
  250. package/src/interfaces/rest/schemas/pricing.ts +75 -0
  251. package/src/interfaces/rest/schemas/settings.ts +93 -0
  252. package/src/interfaces/rest/schemas/shipping.ts +164 -0
  253. package/src/interfaces/rest/schemas/tax.ts +148 -0
  254. package/src/kernel/database/schema.ts +12 -0
  255. package/src/kernel/error-mapper.ts +1 -0
  256. package/src/kernel/errors.ts +11 -0
  257. package/src/kernel/hooks/types.ts +1 -0
  258. package/src/kernel/plugin/manifest.ts +38 -2
  259. package/src/modules/analytics/module.ts +10 -0
  260. package/src/modules/analytics/reports.ts +311 -0
  261. package/src/modules/analytics/service.ts +23 -0
  262. package/src/modules/cart/repository/index.ts +30 -1
  263. package/src/modules/cart/schema.ts +2 -0
  264. package/src/modules/cart/schemas.ts +1 -0
  265. package/src/modules/cart/service.ts +101 -0
  266. package/src/modules/catalog/entity-service.ts +195 -6
  267. package/src/modules/catalog/schema.ts +5 -0
  268. package/src/modules/catalog/schemas.ts +18 -1
  269. package/src/modules/catalog/service.ts +32 -2
  270. package/src/modules/documents/module.ts +19 -0
  271. package/src/modules/documents/pdf.ts +101 -0
  272. package/src/modules/documents/render.ts +231 -0
  273. package/src/modules/documents/repository/index.ts +68 -0
  274. package/src/modules/documents/schema.ts +44 -0
  275. package/src/modules/documents/service.ts +176 -0
  276. package/src/modules/fulfillment/service.ts +139 -1
  277. package/src/modules/media/service.ts +40 -0
  278. package/src/modules/orders/repository/index.ts +127 -1
  279. package/src/modules/orders/schema.ts +54 -1
  280. package/src/modules/orders/service.ts +739 -24
  281. package/src/modules/pricing/repository/index.ts +34 -0
  282. package/src/modules/pricing/service.ts +100 -1
  283. package/src/modules/settings/module.ts +18 -0
  284. package/src/modules/settings/repository/index.ts +59 -0
  285. package/src/modules/settings/schema.ts +25 -0
  286. package/src/modules/settings/service.ts +82 -0
  287. package/src/modules/shipping/calculator.ts +27 -0
  288. package/src/modules/shipping/module.ts +6 -2
  289. package/src/modules/shipping/repository/index.ts +136 -2
  290. package/src/modules/shipping/schema.ts +58 -0
  291. package/src/modules/shipping/service.ts +260 -1
  292. package/src/modules/tax/adapter.ts +9 -0
  293. package/src/modules/tax/module.ts +6 -2
  294. package/src/modules/tax/repository/index.ts +169 -2
  295. package/src/modules/tax/schema.ts +57 -0
  296. package/src/modules/tax/service.ts +313 -2
  297. package/src/runtime/kernel-modules.ts +4 -0
  298. package/src/runtime/kernel-types.ts +6 -0
  299. package/src/runtime/server.ts +36 -3
  300. package/src/test-utils/create-plugin-test-app.ts +17 -4
  301. package/src/test-utils/rest-api-test-utils.ts +6 -0
@@ -0,0 +1,119 @@
1
+ import { resolveOrgId } from "../../auth/org.js";
2
+ import { CommerceValidationError } from "../../kernel/errors.js";
3
+ import { Err, Ok } from "../../kernel/result.js";
4
+ import { buildPdf } from "./pdf.js";
5
+ import { invoiceHtml, invoicePdfOps, receiptHtml, } from "./render.js";
6
+ const DEFAULT_INVOICE_PREFIX = "INV-";
7
+ /**
8
+ * Order document rendering + fiscal numbering (issue #47).
9
+ */
10
+ export class DocumentsService {
11
+ repository;
12
+ services;
13
+ constructor(deps) {
14
+ this.repository = deps.repository;
15
+ this.services = deps.services;
16
+ }
17
+ get orders() {
18
+ return this.services.orders;
19
+ }
20
+ get settings() {
21
+ return this.services.settings;
22
+ }
23
+ async brandingFor(orgId, ctx) {
24
+ return (await this.settings.read(orgId, "branding", ctx));
25
+ }
26
+ /**
27
+ * Issues (or returns the previously issued) fiscal invoice number for an
28
+ * order. Idempotent per (org, order): once handed out, the number never
29
+ * changes. Sequence allocation is atomic; a lost creation race falls back
30
+ * to the winner's document.
31
+ */
32
+ async issueInvoiceNumber(order, ctx) {
33
+ const orgId = order.organizationId;
34
+ const existing = await this.repository.findDocument(orgId, order.id, "invoice", ctx);
35
+ if (existing)
36
+ return existing;
37
+ const documentsSettings = await this.settings.read(orgId, "documents", ctx);
38
+ const prefix = typeof documentsSettings.invoicePrefix === "string"
39
+ ? documentsSettings.invoicePrefix
40
+ : DEFAULT_INVOICE_PREFIX;
41
+ const value = await this.repository.allocate(orgId, "invoice", ctx);
42
+ const documentNumber = `${prefix}${String(value).padStart(6, "0")}`;
43
+ try {
44
+ return await this.repository.createDocument({ organizationId: orgId, orderId: order.id, type: "invoice", documentNumber }, ctx);
45
+ }
46
+ catch (error) {
47
+ // Unique (org, order, type) — a concurrent request won; use its number.
48
+ const winner = await this.repository.findDocument(orgId, order.id, "invoice", ctx);
49
+ if (winner)
50
+ return winner;
51
+ throw error;
52
+ }
53
+ }
54
+ async loadOrder(orderId, actor, ctx) {
55
+ return this.orders.getById(orderId, actor, ctx);
56
+ }
57
+ async renderInvoiceHtml(orderId, actor, ctx) {
58
+ const order = await this.loadOrder(orderId, actor, ctx);
59
+ if (!order.ok)
60
+ return order;
61
+ const branding = await this.brandingFor(order.value.organizationId, ctx);
62
+ const doc = await this.issueInvoiceNumber(order.value, ctx);
63
+ return Ok({
64
+ html: invoiceHtml({ order: order.value, branding, invoiceNumber: doc.documentNumber }),
65
+ invoiceNumber: doc.documentNumber,
66
+ });
67
+ }
68
+ async renderInvoicePdf(orderId, actor, ctx) {
69
+ const order = await this.loadOrder(orderId, actor, ctx);
70
+ if (!order.ok)
71
+ return order;
72
+ const branding = await this.brandingFor(order.value.organizationId, ctx);
73
+ const doc = await this.issueInvoiceNumber(order.value, ctx);
74
+ const pages = invoicePdfOps({
75
+ order: order.value,
76
+ branding,
77
+ invoiceNumber: doc.documentNumber,
78
+ });
79
+ return Ok({ pdf: buildPdf(pages), invoiceNumber: doc.documentNumber });
80
+ }
81
+ async renderReceiptHtml(orderId, actor, ctx) {
82
+ const order = await this.loadOrder(orderId, actor, ctx);
83
+ if (!order.ok)
84
+ return order;
85
+ const branding = await this.brandingFor(order.value.organizationId, ctx);
86
+ return Ok({ html: receiptHtml({ order: order.value, branding }) });
87
+ }
88
+ /**
89
+ * Emails the invoice via the configured email adapter. The adapter's
90
+ * template contract is (template, to, data) — the rendered HTML and the
91
+ * fiscal number ride in `data` so template-based adapters can use either.
92
+ */
93
+ async emailInvoice(orderId, to, actor, ctx) {
94
+ const email = this.services.email;
95
+ if (!email) {
96
+ return Err(new CommerceValidationError("No email adapter is configured."));
97
+ }
98
+ const rendered = await this.renderInvoiceHtml(orderId, actor, ctx);
99
+ if (!rendered.ok)
100
+ return rendered;
101
+ const order = await this.loadOrder(orderId, actor, ctx);
102
+ if (!order.ok)
103
+ return order;
104
+ await email.send({
105
+ template: "order-invoice",
106
+ to,
107
+ data: {
108
+ orgId: resolveOrgId(actor ?? ctx?.actor ?? null),
109
+ orderId,
110
+ orderNumber: order.value.orderNumber,
111
+ invoiceNumber: rendered.value.invoiceNumber,
112
+ grandTotal: order.value.grandTotal,
113
+ currency: order.value.currency,
114
+ html: rendered.value.html,
115
+ },
116
+ });
117
+ return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to });
118
+ }
119
+ }
@@ -37,6 +37,24 @@ export declare class FulfillmentService {
37
37
  private strategies;
38
38
  constructor(deps: FulfillmentServiceDeps);
39
39
  fulfillOrder(orderId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>>;
40
+ /**
41
+ * Records a fulfillment (e.g. a shipment) for a subset of an order's line
42
+ * items, with optional carrier/tracking details. Supports partial
43
+ * fulfillment (per-line quantities) and multiple fulfillments per order.
44
+ */
45
+ createFulfillment(input: {
46
+ orderId: string;
47
+ lineItems: Array<{
48
+ orderLineItemId: string;
49
+ quantity: number;
50
+ }>;
51
+ carrier?: string;
52
+ trackingNumber?: string;
53
+ trackingUrl?: string;
54
+ type?: string;
55
+ status?: string;
56
+ metadata?: Record<string, unknown>;
57
+ }, actor?: Actor | null, ctx?: TxContext): Promise<Result<FulfillmentRecord>>;
40
58
  getByOrderId(orderId: string, ctx?: TxContext): Promise<Result<FulfillmentRecord[]>>;
41
59
  updateTracking(input: {
42
60
  fulfillmentId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/service.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { createHmac } from "node:crypto";
2
2
  import { resolveOrgId } from "../../auth/org.js";
3
- import { CommerceNotFoundError } from "../../kernel/errors.js";
3
+ import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
4
4
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
5
5
  import { createHookContext } from "../../kernel/hooks/create-context.js";
6
6
  import { Err, Ok } from "../../kernel/result.js";
@@ -198,6 +198,90 @@ export class FulfillmentService {
198
198
  }
199
199
  return Ok(undefined);
200
200
  }
201
+ /**
202
+ * Records a fulfillment (e.g. a shipment) for a subset of an order's line
203
+ * items, with optional carrier/tracking details. Supports partial
204
+ * fulfillment (per-line quantities) and multiple fulfillments per order.
205
+ */
206
+ async createFulfillment(input, actor, ctx) {
207
+ const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
208
+ const order = await this.deps.ordersRepository.findById(orgId, input.orderId, ctx);
209
+ if (!order)
210
+ return Err(new CommerceNotFoundError("Order not found."));
211
+ const orderLines = await this.deps.ordersRepository.findLineItemsByOrderId(input.orderId, ctx);
212
+ const linesById = new Map(orderLines.map((li) => [li.id, li]));
213
+ // Validate every requested line before writing anything: it must belong
214
+ // to the order, and requested + already-fulfilled must not exceed ordered.
215
+ const alreadyFulfilled = new Map();
216
+ for (const req of input.lineItems) {
217
+ const line = linesById.get(req.orderLineItemId);
218
+ if (!line) {
219
+ return Err(new CommerceValidationError(`Line item ${req.orderLineItemId} does not belong to this order.`));
220
+ }
221
+ const fulfilled = await this.deps.repository.getFulfilledQuantity(req.orderLineItemId, ctx);
222
+ alreadyFulfilled.set(req.orderLineItemId, fulfilled);
223
+ if (fulfilled + req.quantity > line.quantity) {
224
+ return Err(new CommerceValidationError(`Cannot fulfill ${req.quantity} of "${line.title}" — only ${line.quantity - fulfilled} remaining.`));
225
+ }
226
+ }
227
+ const status = input.status ?? "shipped";
228
+ const created = await this.deps.repository.create({
229
+ orderId: order.id,
230
+ type: input.type ?? "physical",
231
+ status,
232
+ carrier: input.carrier ?? null,
233
+ trackingNumber: input.trackingNumber ?? null,
234
+ trackingUrl: input.trackingUrl ?? null,
235
+ ...(status === "shipped" ? { shippedAt: new Date() } : {}),
236
+ ...(status === "delivered" ? { deliveredAt: new Date() } : {}),
237
+ ...(order.customerId != null ? { customerId: order.customerId } : {}),
238
+ metadata: input.metadata ?? {},
239
+ }, ctx);
240
+ await this.deps.repository.createLineItems(input.lineItems.map((li) => ({
241
+ fulfillmentId: created.id,
242
+ orderLineItemId: li.orderLineItemId,
243
+ quantity: li.quantity,
244
+ })), ctx);
245
+ await this.deps.repository.createEvent({
246
+ fulfillmentId: created.id,
247
+ eventType: "created",
248
+ toStatus: status,
249
+ ...(actor?.userId !== undefined ? { actorId: actor.userId } : {}),
250
+ description: input.trackingNumber
251
+ ? `Shipment recorded (${input.trackingNumber})`
252
+ : "Fulfillment recorded",
253
+ }, ctx);
254
+ // Reflect per-line fulfillment progress on the order line items
255
+ for (const req of input.lineItems) {
256
+ const line = linesById.get(req.orderLineItemId);
257
+ const total = (alreadyFulfilled.get(req.orderLineItemId) ?? 0) + req.quantity;
258
+ await this.deps.ordersRepository.updateLineItem(req.orderLineItemId, { fulfillmentStatus: total >= line.quantity ? "fulfilled" : "partial" }, ctx);
259
+ }
260
+ const record = {
261
+ ...toServiceRecord(created, input.lineItems.map((li) => ({
262
+ id: "",
263
+ fulfillmentId: created.id,
264
+ orderLineItemId: li.orderLineItemId,
265
+ quantity: li.quantity,
266
+ }))),
267
+ lineItems: input.lineItems.map((li) => ({
268
+ id: li.orderLineItemId,
269
+ title: linesById.get(li.orderLineItemId)?.title ?? "",
270
+ quantity: li.quantity,
271
+ })),
272
+ };
273
+ const afterHooks = this.deps.hooks.resolve("fulfillment.afterCreate");
274
+ const hookCtx = createHookContext({
275
+ actor: actor ?? ctx?.actor ?? null,
276
+ tx: ctx?.tx ?? null,
277
+ logger: createLogger("fulfillment"),
278
+ services: this.deps.services,
279
+ context: { moduleName: "fulfillment" },
280
+ database: { db: this.deps.database.db },
281
+ });
282
+ await runAfterHooks(afterHooks, null, record, "create", hookCtx);
283
+ return Ok(record);
284
+ }
201
285
  async getByOrderId(orderId, ctx) {
202
286
  const dbRecords = await this.deps.repository.findByOrderId(orderId, ctx);
203
287
  // Hydrate each record with its associated line items
@@ -19,6 +19,15 @@ export interface AttachMediaInput {
19
19
  variantId?: string;
20
20
  sortOrder?: number;
21
21
  }
22
+ export interface AttachedMedia {
23
+ mediaAssetId: string;
24
+ role: string;
25
+ sortOrder: number;
26
+ variantId: string | null;
27
+ url: string;
28
+ alt: string | null;
29
+ contentType: string;
30
+ }
22
31
  interface MediaServiceDeps {
23
32
  repository: MediaRepository;
24
33
  catalogRepository: CatalogRepository;
@@ -40,6 +49,15 @@ export declare class MediaService {
40
49
  delete(id: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>>;
41
50
  list(prefix?: string): Promise<Result<StoredFile[]>>;
42
51
  attachToEntity(input: AttachMediaInput, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>>;
52
+ /**
53
+ * Media attached to an entity, resolved to public URLs and ordered by
54
+ * sortOrder. Powers catalog `?include=media` hydration. Returns entity-level
55
+ * links only unless a specific variantId is requested.
56
+ */
57
+ listEntityMedia(entityId: string, opts?: {
58
+ variantId?: string;
59
+ orgId?: string;
60
+ }, ctx?: TxContext): Promise<Result<AttachedMedia[]>>;
43
61
  }
44
62
  export {};
45
63
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/media/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAK9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAGrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,CAAC;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACxB,UAAU,EAAE,eAAe,CAAC;IAC5B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;CACxB;AAkBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAyBtE;AAED,qBAAa,YAAY;IAIX,OAAO,CAAC,IAAI;IAHxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;gBAE5B,IAAI,EAAE,gBAAgB;IAKpC,MAAM,CACV,KAAK,EAAE,gBAAgB,EACvB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAkEzC,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAOpB,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,SAAS,SAAU,EACnB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAOpB,MAAM,CACV,EAAE,EAAE,MAAM,EACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAalB,IAAI,CAAC,MAAM,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAMhD,cAAc,CAClB,KAAK,EAAE,gBAAgB,EACvB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CA2BzB"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/media/service.ts"],"names":[],"mappings":"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"}
@@ -146,4 +146,30 @@ export class MediaService {
146
146
  }, ctx);
147
147
  return Ok(undefined);
148
148
  }
149
+ /**
150
+ * Media attached to an entity, resolved to public URLs and ordered by
151
+ * sortOrder. Powers catalog `?include=media` hydration. Returns entity-level
152
+ * links only unless a specific variantId is requested.
153
+ */
154
+ async listEntityMedia(entityId, opts, ctx) {
155
+ const links = await this.repo.findEntityMedia(entityId, opts?.variantId, ctx);
156
+ const out = [];
157
+ for (const link of links) {
158
+ const asset = await this.repo.findAssetById(link.mediaAssetId, ctx, opts?.orgId);
159
+ if (!asset)
160
+ continue;
161
+ const urlResult = await this.deps.storage.getUrl(asset.storageKey);
162
+ out.push({
163
+ mediaAssetId: link.mediaAssetId,
164
+ role: link.role,
165
+ sortOrder: link.sortOrder,
166
+ variantId: link.variantId ?? null,
167
+ url: urlResult.ok ? urlResult.value : "",
168
+ alt: asset.alt ?? null,
169
+ contentType: asset.contentType,
170
+ });
171
+ }
172
+ out.sort((a, b) => a.sortOrder - b.sortOrder);
173
+ return Ok(out);
174
+ }
149
175
  }
@@ -1,6 +1,6 @@
1
1
  import type { TxContext } from "../../../kernel/database/tx-context.js";
2
2
  import type { DrizzleDatabase } from "../../../kernel/database/drizzle-db.js";
3
- import { orders, orderLineItems, orderStatusHistory } from "../schema.js";
3
+ import { orders, orderLineItems, orderNotes, orderRefunds, orderStatusHistory } from "../schema.js";
4
4
  export interface OrderLookupRow {
5
5
  id: string;
6
6
  orderNumber: string;
@@ -18,6 +18,10 @@ export type OrderLineItem = typeof orderLineItems.$inferSelect;
18
18
  export type OrderLineItemInsert = typeof orderLineItems.$inferInsert;
19
19
  export type OrderStatusHistory = typeof orderStatusHistory.$inferSelect;
20
20
  export type OrderStatusHistoryInsert = typeof orderStatusHistory.$inferInsert;
21
+ export type OrderRefund = typeof orderRefunds.$inferSelect;
22
+ export type OrderRefundInsert = typeof orderRefunds.$inferInsert;
23
+ export type OrderNote = typeof orderNotes.$inferSelect;
24
+ export type OrderNoteInsert = typeof orderNotes.$inferInsert;
21
25
  /**
22
26
  * OrdersRepository provides type-safe database operations for orders.
23
27
  *
@@ -44,6 +48,7 @@ export declare class OrdersRepository {
44
48
  limit?: number;
45
49
  offset?: number;
46
50
  }, ctx?: TxContext): Promise<Order[]>;
51
+ findByIdempotencyKey(orgId: string, idempotencyKey: string, ctx?: TxContext): Promise<Order | undefined>;
47
52
  create(data: OrderInsert, ctx?: TxContext): Promise<Order>;
48
53
  update(id: string, data: Partial<Omit<OrderInsert, "id">>, ctx?: TxContext): Promise<Order | undefined>;
49
54
  updateStatus(id: string, currentStatus: string, newStatus: string, ctx?: TxContext): Promise<Order | undefined>;
@@ -62,6 +67,18 @@ export declare class OrdersRepository {
62
67
  order: Order;
63
68
  lineItems: OrderLineItem[];
64
69
  } | undefined>;
70
+ createRefund(data: OrderRefundInsert, ctx?: TxContext): Promise<OrderRefund>;
71
+ findRefundById(orgId: string, id: string, ctx?: TxContext): Promise<OrderRefund | undefined>;
72
+ findRefundsByOrderId(orderId: string, ctx?: TxContext): Promise<OrderRefund[]>;
73
+ markRefundUndone(id: string, undoneBy: string, ctx?: TxContext): Promise<OrderRefund | undefined>;
74
+ /**
75
+ * Sum of completed refunds performed by an operator for the local calendar
76
+ * day in the given timezone — the daily-cap accounting query.
77
+ */
78
+ sumRefundsByOperatorToday(orgId: string, performedBy: string, timezone: string, ctx?: TxContext): Promise<number>;
79
+ createNote(data: OrderNoteInsert, ctx?: TxContext): Promise<OrderNote>;
80
+ findNotesByOrderId(orderId: string, ctx?: TxContext): Promise<OrderNote[]>;
81
+ deleteNote(orgId: string, orderId: string, noteId: string, ctx?: TxContext): Promise<boolean>;
65
82
  getNextOrderNumber(ctx?: TxContext): Promise<string>;
66
83
  }
67
84
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/orders/repository/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/orders/repository/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { eq, and, or, gte, lte, desc, sql } from "drizzle-orm";
2
- import { orders, orderLineItems, orderStatusHistory } from "../schema.js";
2
+ import { orders, orderLineItems, orderNotes, orderRefunds, orderStatusHistory } from "../schema.js";
3
3
  import { customers } from "../../customers/schema.js";
4
4
  /**
5
5
  * OrdersRepository provides type-safe database operations for orders.
@@ -106,6 +106,14 @@ export class OrdersRepository {
106
106
  }
107
107
  return query;
108
108
  }
109
+ async findByIdempotencyKey(orgId, idempotencyKey, ctx) {
110
+ const db = this.getDb(ctx);
111
+ const rows = await db
112
+ .select()
113
+ .from(orders)
114
+ .where(and(eq(orders.organizationId, orgId), eq(orders.idempotencyKey, idempotencyKey)));
115
+ return rows[0];
116
+ }
109
117
  async create(data, ctx) {
110
118
  const db = this.getDb(ctx);
111
119
  const rows = await db.insert(orders).values(data).returning();
@@ -223,6 +231,83 @@ export class OrdersRepository {
223
231
  return { order, lineItems };
224
232
  }
225
233
  // ─────────────────────────────────────────────────────────────────────────────
234
+ // Line-level refunds (issue #52)
235
+ // ─────────────────────────────────────────────────────────────────────────────
236
+ async createRefund(data, ctx) {
237
+ const db = this.getDb(ctx);
238
+ const rows = await db.insert(orderRefunds).values(data).returning();
239
+ return rows[0];
240
+ }
241
+ async findRefundById(orgId, id, ctx) {
242
+ const db = this.getDb(ctx);
243
+ const rows = await db
244
+ .select()
245
+ .from(orderRefunds)
246
+ .where(and(eq(orderRefunds.organizationId, orgId), eq(orderRefunds.id, id)));
247
+ return rows[0];
248
+ }
249
+ async findRefundsByOrderId(orderId, ctx) {
250
+ const db = this.getDb(ctx);
251
+ return db
252
+ .select()
253
+ .from(orderRefunds)
254
+ .where(eq(orderRefunds.orderId, orderId))
255
+ .orderBy(desc(orderRefunds.createdAt));
256
+ }
257
+ async markRefundUndone(id, undoneBy, ctx) {
258
+ const db = this.getDb(ctx);
259
+ const rows = await db
260
+ .update(orderRefunds)
261
+ .set({ status: "undone", undoneAt: new Date(), undoneBy })
262
+ .where(and(eq(orderRefunds.id, id), eq(orderRefunds.status, "completed")))
263
+ .returning();
264
+ return rows[0];
265
+ }
266
+ /**
267
+ * Sum of completed refunds performed by an operator for the local calendar
268
+ * day in the given timezone — the daily-cap accounting query.
269
+ */
270
+ async sumRefundsByOperatorToday(orgId, performedBy, timezone, ctx) {
271
+ const db = this.getDb(ctx);
272
+ const result = await db.execute(sql `
273
+ SELECT COALESCE(sum(amount), 0)::int AS "total"
274
+ FROM order_refunds
275
+ WHERE organization_id = ${orgId}
276
+ AND performed_by = ${performedBy}
277
+ AND status = 'completed'
278
+ AND (created_at AT TIME ZONE ${timezone})::date = (now() AT TIME ZONE ${timezone})::date
279
+ `);
280
+ const rows = Array.isArray(result)
281
+ ? result
282
+ : (result.rows ?? []);
283
+ const total = rows[0]?.total;
284
+ return typeof total === "bigint" ? Number(total) : (total ?? 0);
285
+ }
286
+ // ─────────────────────────────────────────────────────────────────────────────
287
+ // Order notes (issue #56)
288
+ // ─────────────────────────────────────────────────────────────────────────────
289
+ async createNote(data, ctx) {
290
+ const db = this.getDb(ctx);
291
+ const rows = await db.insert(orderNotes).values(data).returning();
292
+ return rows[0];
293
+ }
294
+ async findNotesByOrderId(orderId, ctx) {
295
+ const db = this.getDb(ctx);
296
+ return db
297
+ .select()
298
+ .from(orderNotes)
299
+ .where(eq(orderNotes.orderId, orderId))
300
+ .orderBy(desc(orderNotes.pinned), desc(orderNotes.createdAt));
301
+ }
302
+ async deleteNote(orgId, orderId, noteId, ctx) {
303
+ const db = this.getDb(ctx);
304
+ const rows = await db
305
+ .delete(orderNotes)
306
+ .where(and(eq(orderNotes.id, noteId), eq(orderNotes.orderId, orderId), eq(orderNotes.organizationId, orgId)))
307
+ .returning();
308
+ return rows.length > 0;
309
+ }
310
+ // ─────────────────────────────────────────────────────────────────────────────
226
311
  // Order Number Generation
227
312
  // ─────────────────────────────────────────────────────────────────────────────
228
313
  async getNextOrderNumber(ctx) {