@endora-commerce/mod-returns 0.100.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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/admin/api/returns-client.d.ts +69 -0
  4. package/dist/admin/api/returns-client.d.ts.map +1 -0
  5. package/dist/admin/api/returns-client.js +36 -0
  6. package/dist/admin/api/returns-client.js.map +1 -0
  7. package/dist/admin/index.d.ts +37 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +57 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/ReturnDeliveryMethodsPage.d.ts +5 -0
  12. package/dist/admin/pages/ReturnDeliveryMethodsPage.d.ts.map +1 -0
  13. package/dist/admin/pages/ReturnDeliveryMethodsPage.js +44 -0
  14. package/dist/admin/pages/ReturnDeliveryMethodsPage.js.map +1 -0
  15. package/dist/admin/pages/ReturnDetail.d.ts +5 -0
  16. package/dist/admin/pages/ReturnDetail.d.ts.map +1 -0
  17. package/dist/admin/pages/ReturnDetail.js +115 -0
  18. package/dist/admin/pages/ReturnDetail.js.map +1 -0
  19. package/dist/admin/pages/ReturnReasonsPage.d.ts +5 -0
  20. package/dist/admin/pages/ReturnReasonsPage.d.ts.map +1 -0
  21. package/dist/admin/pages/ReturnReasonsPage.js +44 -0
  22. package/dist/admin/pages/ReturnReasonsPage.js.map +1 -0
  23. package/dist/admin/pages/ReturnStatusesConfigPage.d.ts +5 -0
  24. package/dist/admin/pages/ReturnStatusesConfigPage.d.ts.map +1 -0
  25. package/dist/admin/pages/ReturnStatusesConfigPage.js +71 -0
  26. package/dist/admin/pages/ReturnStatusesConfigPage.js.map +1 -0
  27. package/dist/admin/pages/ReturnsList.d.ts +5 -0
  28. package/dist/admin/pages/ReturnsList.d.ts.map +1 -0
  29. package/dist/admin/pages/ReturnsList.js +189 -0
  30. package/dist/admin/pages/ReturnsList.js.map +1 -0
  31. package/dist/backend/domain/default-reasons.d.ts +14 -0
  32. package/dist/backend/domain/default-reasons.d.ts.map +1 -0
  33. package/dist/backend/domain/default-reasons.js +9 -0
  34. package/dist/backend/domain/default-reasons.js.map +1 -0
  35. package/dist/backend/domain/free-return-window.d.ts +2 -0
  36. package/dist/backend/domain/free-return-window.d.ts.map +1 -0
  37. package/dist/backend/domain/free-return-window.js +19 -0
  38. package/dist/backend/domain/free-return-window.js.map +1 -0
  39. package/dist/backend/domain/refund-math.d.ts +19 -0
  40. package/dist/backend/domain/refund-math.d.ts.map +1 -0
  41. package/dist/backend/domain/refund-math.js +27 -0
  42. package/dist/backend/domain/refund-math.js.map +1 -0
  43. package/dist/backend/domain/return-status-graph.d.ts +91 -0
  44. package/dist/backend/domain/return-status-graph.d.ts.map +1 -0
  45. package/dist/backend/domain/return-status-graph.js +143 -0
  46. package/dist/backend/domain/return-status-graph.js.map +1 -0
  47. package/dist/backend/email-templates/return-authorized.d.ts +11 -0
  48. package/dist/backend/email-templates/return-authorized.d.ts.map +1 -0
  49. package/dist/backend/email-templates/return-authorized.js +18 -0
  50. package/dist/backend/email-templates/return-authorized.js.map +1 -0
  51. package/dist/backend/email-templates/return-rejected.d.ts +11 -0
  52. package/dist/backend/email-templates/return-rejected.d.ts.map +1 -0
  53. package/dist/backend/email-templates/return-rejected.js +20 -0
  54. package/dist/backend/email-templates/return-rejected.js.map +1 -0
  55. package/dist/backend/email-templates/transactional-defaults.d.ts +11 -0
  56. package/dist/backend/email-templates/transactional-defaults.d.ts.map +1 -0
  57. package/dist/backend/email-templates/transactional-defaults.js +64 -0
  58. package/dist/backend/email-templates/transactional-defaults.js.map +1 -0
  59. package/dist/backend/entities/refund.entity.d.ts +41 -0
  60. package/dist/backend/entities/refund.entity.d.ts.map +1 -0
  61. package/dist/backend/entities/refund.entity.js +122 -0
  62. package/dist/backend/entities/refund.entity.js.map +1 -0
  63. package/dist/backend/entities/return-case-attachment.entity.d.ts +16 -0
  64. package/dist/backend/entities/return-case-attachment.entity.d.ts.map +1 -0
  65. package/dist/backend/entities/return-case-attachment.entity.js +53 -0
  66. package/dist/backend/entities/return-case-attachment.entity.js.map +1 -0
  67. package/dist/backend/entities/return-case-comment.entity.d.ts +20 -0
  68. package/dist/backend/entities/return-case-comment.entity.d.ts.map +1 -0
  69. package/dist/backend/entities/return-case-comment.entity.js +70 -0
  70. package/dist/backend/entities/return-case-comment.entity.js.map +1 -0
  71. package/dist/backend/entities/return-case-item.entity.d.ts +25 -0
  72. package/dist/backend/entities/return-case-item.entity.d.ts.map +1 -0
  73. package/dist/backend/entities/return-case-item.entity.js +87 -0
  74. package/dist/backend/entities/return-case-item.entity.js.map +1 -0
  75. package/dist/backend/entities/return-case.entity.d.ts +41 -0
  76. package/dist/backend/entities/return-case.entity.d.ts.map +1 -0
  77. package/dist/backend/entities/return-case.entity.js +155 -0
  78. package/dist/backend/entities/return-case.entity.js.map +1 -0
  79. package/dist/backend/entities/return-delivery-method.entity.d.ts +18 -0
  80. package/dist/backend/entities/return-delivery-method.entity.d.ts.map +1 -0
  81. package/dist/backend/entities/return-delivery-method.entity.js +63 -0
  82. package/dist/backend/entities/return-delivery-method.entity.js.map +1 -0
  83. package/dist/backend/entities/return-list-saved-view.entity.d.ts +24 -0
  84. package/dist/backend/entities/return-list-saved-view.entity.d.ts.map +1 -0
  85. package/dist/backend/entities/return-list-saved-view.entity.js +74 -0
  86. package/dist/backend/entities/return-list-saved-view.entity.js.map +1 -0
  87. package/dist/backend/entities/return-reason.entity.d.ts +21 -0
  88. package/dist/backend/entities/return-reason.entity.d.ts.map +1 -0
  89. package/dist/backend/entities/return-reason.entity.js +65 -0
  90. package/dist/backend/entities/return-reason.entity.js.map +1 -0
  91. package/dist/backend/entities/return-shipment.entity.d.ts +22 -0
  92. package/dist/backend/entities/return-shipment.entity.d.ts.map +1 -0
  93. package/dist/backend/entities/return-shipment.entity.js +71 -0
  94. package/dist/backend/entities/return-shipment.entity.js.map +1 -0
  95. package/dist/backend/entities/return-status-transition.entity.d.ts +17 -0
  96. package/dist/backend/entities/return-status-transition.entity.d.ts.map +1 -0
  97. package/dist/backend/entities/return-status-transition.entity.js +55 -0
  98. package/dist/backend/entities/return-status-transition.entity.js.map +1 -0
  99. package/dist/backend/entities/return-status.entity.d.ts +29 -0
  100. package/dist/backend/entities/return-status.entity.d.ts.map +1 -0
  101. package/dist/backend/entities/return-status.entity.js +90 -0
  102. package/dist/backend/entities/return-status.entity.js.map +1 -0
  103. package/dist/backend/events/return-status-events.d.ts +44 -0
  104. package/dist/backend/events/return-status-events.d.ts.map +1 -0
  105. package/dist/backend/events/return-status-events.js +50 -0
  106. package/dist/backend/events/return-status-events.js.map +1 -0
  107. package/dist/backend/index.d.ts +106 -0
  108. package/dist/backend/index.d.ts.map +1 -0
  109. package/dist/backend/index.js +116 -0
  110. package/dist/backend/index.js.map +1 -0
  111. package/dist/backend/plugin.d.ts +33 -0
  112. package/dist/backend/plugin.d.ts.map +1 -0
  113. package/dist/backend/plugin.js +124 -0
  114. package/dist/backend/plugin.js.map +1 -0
  115. package/dist/backend/routes.admin.d.ts +38 -0
  116. package/dist/backend/routes.admin.d.ts.map +1 -0
  117. package/dist/backend/routes.admin.js +181 -0
  118. package/dist/backend/routes.admin.js.map +1 -0
  119. package/dist/backend/routes.customer.d.ts +22 -0
  120. package/dist/backend/routes.customer.d.ts.map +1 -0
  121. package/dist/backend/routes.customer.js +56 -0
  122. package/dist/backend/routes.customer.js.map +1 -0
  123. package/dist/backend/services/notification-context.d.ts +47 -0
  124. package/dist/backend/services/notification-context.d.ts.map +1 -0
  125. package/dist/backend/services/notification-context.js +49 -0
  126. package/dist/backend/services/notification-context.js.map +1 -0
  127. package/dist/backend/services/return-attachment-service.d.ts +20 -0
  128. package/dist/backend/services/return-attachment-service.d.ts.map +1 -0
  129. package/dist/backend/services/return-attachment-service.js +48 -0
  130. package/dist/backend/services/return-attachment-service.js.map +1 -0
  131. package/dist/backend/services/return-authorization-service.d.ts +53 -0
  132. package/dist/backend/services/return-authorization-service.d.ts.map +1 -0
  133. package/dist/backend/services/return-authorization-service.js +72 -0
  134. package/dist/backend/services/return-authorization-service.js.map +1 -0
  135. package/dist/backend/services/return-case-service.d.ts +44 -0
  136. package/dist/backend/services/return-case-service.d.ts.map +1 -0
  137. package/dist/backend/services/return-case-service.js +260 -0
  138. package/dist/backend/services/return-case-service.js.map +1 -0
  139. package/dist/backend/services/return-comment-service.d.ts +43 -0
  140. package/dist/backend/services/return-comment-service.d.ts.map +1 -0
  141. package/dist/backend/services/return-comment-service.js +109 -0
  142. package/dist/backend/services/return-comment-service.js.map +1 -0
  143. package/dist/backend/services/return-delivery-method-service.d.ts +44 -0
  144. package/dist/backend/services/return-delivery-method-service.d.ts.map +1 -0
  145. package/dist/backend/services/return-delivery-method-service.js +114 -0
  146. package/dist/backend/services/return-delivery-method-service.js.map +1 -0
  147. package/dist/backend/services/return-email-notifier.d.ts +89 -0
  148. package/dist/backend/services/return-email-notifier.d.ts.map +1 -0
  149. package/dist/backend/services/return-email-notifier.js +128 -0
  150. package/dist/backend/services/return-email-notifier.js.map +1 -0
  151. package/dist/backend/services/return-export-service.d.ts +16 -0
  152. package/dist/backend/services/return-export-service.d.ts.map +1 -0
  153. package/dist/backend/services/return-export-service.js +29 -0
  154. package/dist/backend/services/return-export-service.js.map +1 -0
  155. package/dist/backend/services/return-list-service.d.ts +27 -0
  156. package/dist/backend/services/return-list-service.d.ts.map +1 -0
  157. package/dist/backend/services/return-list-service.js +114 -0
  158. package/dist/backend/services/return-list-service.js.map +1 -0
  159. package/dist/backend/services/return-list-view-service.d.ts +36 -0
  160. package/dist/backend/services/return-list-view-service.d.ts.map +1 -0
  161. package/dist/backend/services/return-list-view-service.js +82 -0
  162. package/dist/backend/services/return-list-view-service.js.map +1 -0
  163. package/dist/backend/services/return-reason-service.d.ts +33 -0
  164. package/dist/backend/services/return-reason-service.d.ts.map +1 -0
  165. package/dist/backend/services/return-reason-service.js +90 -0
  166. package/dist/backend/services/return-reason-service.js.map +1 -0
  167. package/dist/backend/services/return-settlement-service.d.ts +67 -0
  168. package/dist/backend/services/return-settlement-service.d.ts.map +1 -0
  169. package/dist/backend/services/return-settlement-service.js +295 -0
  170. package/dist/backend/services/return-settlement-service.js.map +1 -0
  171. package/dist/backend/services/return-shipment-service.d.ts +40 -0
  172. package/dist/backend/services/return-shipment-service.d.ts.map +1 -0
  173. package/dist/backend/services/return-shipment-service.js +113 -0
  174. package/dist/backend/services/return-shipment-service.js.map +1 -0
  175. package/dist/backend/services/return-status-graph-service.d.ts +59 -0
  176. package/dist/backend/services/return-status-graph-service.d.ts.map +1 -0
  177. package/dist/backend/services/return-status-graph-service.js +197 -0
  178. package/dist/backend/services/return-status-graph-service.js.map +1 -0
  179. package/dist/backend/services/return-transition-service.d.ts +48 -0
  180. package/dist/backend/services/return-transition-service.d.ts.map +1 -0
  181. package/dist/backend/services/return-transition-service.js +116 -0
  182. package/dist/backend/services/return-transition-service.js.map +1 -0
  183. package/dist/backend/services/returns-seeder.d.ts +18 -0
  184. package/dist/backend/services/returns-seeder.d.ts.map +1 -0
  185. package/dist/backend/services/returns-seeder.js +63 -0
  186. package/dist/backend/services/returns-seeder.js.map +1 -0
  187. package/dist/backend/services/rma-number-generator.d.ts +35 -0
  188. package/dist/backend/services/rma-number-generator.d.ts.map +1 -0
  189. package/dist/backend/services/rma-number-generator.js +45 -0
  190. package/dist/backend/services/rma-number-generator.js.map +1 -0
  191. package/dist/manifest.d.ts +182 -0
  192. package/dist/manifest.d.ts.map +1 -0
  193. package/dist/manifest.js +216 -0
  194. package/dist/manifest.js.map +1 -0
  195. package/dist/migrations/20260625T144227_returns_init.d.ts +15 -0
  196. package/dist/migrations/20260625T144227_returns_init.d.ts.map +1 -0
  197. package/dist/migrations/20260625T144227_returns_init.js +241 -0
  198. package/dist/migrations/20260625T144227_returns_init.js.map +1 -0
  199. package/dist/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.d.ts +25 -0
  200. package/dist/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.d.ts.map +1 -0
  201. package/dist/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.js +46 -0
  202. package/dist/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.js.map +1 -0
  203. package/dist/migrations/index.d.ts +28 -0
  204. package/dist/migrations/index.d.ts.map +1 -0
  205. package/dist/migrations/index.js +31 -0
  206. package/dist/migrations/index.js.map +1 -0
  207. package/docs/returns.md +103 -0
  208. package/i18n/en.json +28 -0
  209. package/i18n/pl.json +28 -0
  210. package/package.json +101 -0
  211. package/tailwind.css +14 -0
@@ -0,0 +1,56 @@
1
+ import { addReturnAttachmentRequestSchema, createReturnCaseRequestSchema, customerAddCommentRequestSchema, selectReturnDeliveryMethodRequestSchema, } from '@endora-commerce/contracts';
2
+ export async function registerReturnsCustomerRoutes(app, deps) {
3
+ const { caseService, commentService, deliveryMethodService, reasonService, attachmentService, requireCustomer, resolveCustomerAccountId, } = deps;
4
+ app.get('/api/v1/returns/reasons', { preHandler: requireCustomer }, async (request) => {
5
+ const data = await reasonService.listActive(request.query.kind);
6
+ return { data };
7
+ });
8
+ app.get('/api/v1/orders/:orderId/returnable', { preHandler: requireCustomer }, async (request) => {
9
+ const customerAccountId = resolveCustomerAccountId(request);
10
+ const data = await caseService.getReturnable(request.params.orderId, customerAccountId);
11
+ return { data };
12
+ });
13
+ app.get('/api/v1/returns', { preHandler: requireCustomer }, async (request) => {
14
+ const customerAccountId = resolveCustomerAccountId(request);
15
+ const data = await caseService.listForCustomer(customerAccountId);
16
+ return { data };
17
+ });
18
+ app.get('/api/v1/returns/:id', { preHandler: requireCustomer }, async (request) => {
19
+ const customerAccountId = resolveCustomerAccountId(request);
20
+ const data = await caseService.getForCustomer(request.params.id, customerAccountId);
21
+ return { data };
22
+ });
23
+ app.post('/api/v1/returns', { preHandler: requireCustomer, schema: { body: createReturnCaseRequestSchema } }, async (request, reply) => {
24
+ const customerAccountId = resolveCustomerAccountId(request);
25
+ const body = createReturnCaseRequestSchema.parse(request.body);
26
+ const data = await caseService.createCase(body, customerAccountId);
27
+ reply.status(201);
28
+ return { data };
29
+ });
30
+ app.post('/api/v1/returns/:id/comments', { preHandler: requireCustomer, schema: { body: customerAddCommentRequestSchema } }, async (request, reply) => {
31
+ const customerAccountId = resolveCustomerAccountId(request);
32
+ const body = customerAddCommentRequestSchema.parse(request.body);
33
+ const data = await commentService.addByCustomer(request.params.id, customerAccountId, body);
34
+ reply.status(201);
35
+ return { data };
36
+ });
37
+ app.post('/api/v1/returns/:id/select-delivery-method', { preHandler: requireCustomer, schema: { body: selectReturnDeliveryMethodRequestSchema } }, async (request) => {
38
+ const customerAccountId = resolveCustomerAccountId(request);
39
+ const body = selectReturnDeliveryMethodRequestSchema.parse(request.body);
40
+ const data = await deliveryMethodService.selectForCase(request.params.id, customerAccountId, body.returnDeliveryMethodId);
41
+ return { data };
42
+ });
43
+ app.post('/api/v1/returns/:id/cancel', { preHandler: requireCustomer }, async (request) => {
44
+ const customerAccountId = resolveCustomerAccountId(request);
45
+ const data = await caseService.cancelByCustomer(request.params.id, customerAccountId);
46
+ return { data };
47
+ });
48
+ app.post('/api/v1/returns/:id/attachments', { preHandler: requireCustomer, schema: { body: addReturnAttachmentRequestSchema } }, async (request, reply) => {
49
+ const customerAccountId = resolveCustomerAccountId(request);
50
+ const body = addReturnAttachmentRequestSchema.parse(request.body);
51
+ const data = await attachmentService.addToCase(request.params.id, customerAccountId, body);
52
+ reply.status(201);
53
+ return { data };
54
+ });
55
+ }
56
+ //# sourceMappingURL=routes.customer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.customer.js","sourceRoot":"","sources":["../../src/backend/routes.customer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { CustomerAccountReadPort } from '@endora-commerce/contracts';
3
+ import type { CustomerEmailResolver } from './return-email-notifier.js';
4
+ /**
5
+ * The two facts a return notification needs from outside this module
6
+ * (`specs/110-instance-repository/` T118c).
7
+ *
8
+ * Both were `returnsBridge` members — closures a composition root wrote, once in
9
+ * `backend/src/composition.ts` and once in `backend/test/helpers/test-server.ts`,
10
+ * with the same body in each. They are functions of what they read rather than of
11
+ * a `ModuleContext`, so `backend/index.ts` supplies the real inputs and this file
12
+ * is testable over a stub with nothing composed.
13
+ */
14
+ /**
15
+ * Where the authorize / reject e-mail goes.
16
+ *
17
+ * `customer_accounts` publishes the record; this maps it to the one field the
18
+ * notifier needs and answers `null` when no account resolves, which the notifier
19
+ * reports as `no_recipient` rather than treating as sent.
20
+ *
21
+ * **No `catch`, deliberately.** `findById` on a `lazyPort` proxy throws
22
+ * `ModuleDisabledError` when its owner is absent, and reading that as "this buyer
23
+ * has no e-mail address" is the fail-open composition checklist item 7 refuses.
24
+ * `customer_accounts` declares `nonDeactivatable`, so it cannot happen today; the
25
+ * absence of the `catch` is what keeps it fail-closed if that ever changes.
26
+ */
27
+ export declare function createCustomerEmailResolver(accounts: Pick<CustomerAccountReadPort, 'findById'>): CustomerEmailResolver;
28
+ /**
29
+ * The language a channel's e-mail is rendered in.
30
+ *
31
+ * A read of the platform's own `SalesChannel` entity through this module's
32
+ * `EntityManager`, which is what both composition roots did and what `orders`
33
+ * does at the identical site — resolving the language for a transactional e-mail
34
+ * (`order-service.ts`, `sendOrderConfirmation`).
35
+ *
36
+ * **Not `salesChannelResolutionPort`**, though the platform contributes it and it
37
+ * carries `defaultLanguage` on its `CachedChannel`. That port is the *cache*, and
38
+ * swapping a direct read for a cached one changes what this answers for a channel
39
+ * written outside the invalidation path — a design decision about channel reads,
40
+ * not a drain's, and T118c moves a value rather than redesigning it. Constitution
41
+ * XII is untouched either way: this resolves no request channel, it reads one
42
+ * attribute of a channel the return case already names.
43
+ *
44
+ * `en-US` for a channel that is not there is the fallback both roots carried.
45
+ */
46
+ export declare function createChannelLanguageResolver(emFactory: () => EntityManager): (salesChannelId: string) => Promise<string>;
47
+ //# sourceMappingURL=notification-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-context.d.ts","sourceRoot":"","sources":["../../../src/backend/services/notification-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAE1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE;;;;;;;;;GASG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,GAClD,qBAAqB,CAEvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,aAAa,GAC7B,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAG7C"}
@@ -0,0 +1,49 @@
1
+ import { SalesChannel } from '@endora-commerce/platform/kernel';
2
+ /**
3
+ * The two facts a return notification needs from outside this module
4
+ * (`specs/110-instance-repository/` T118c).
5
+ *
6
+ * Both were `returnsBridge` members — closures a composition root wrote, once in
7
+ * `backend/src/composition.ts` and once in `backend/test/helpers/test-server.ts`,
8
+ * with the same body in each. They are functions of what they read rather than of
9
+ * a `ModuleContext`, so `backend/index.ts` supplies the real inputs and this file
10
+ * is testable over a stub with nothing composed.
11
+ */
12
+ /**
13
+ * Where the authorize / reject e-mail goes.
14
+ *
15
+ * `customer_accounts` publishes the record; this maps it to the one field the
16
+ * notifier needs and answers `null` when no account resolves, which the notifier
17
+ * reports as `no_recipient` rather than treating as sent.
18
+ *
19
+ * **No `catch`, deliberately.** `findById` on a `lazyPort` proxy throws
20
+ * `ModuleDisabledError` when its owner is absent, and reading that as "this buyer
21
+ * has no e-mail address" is the fail-open composition checklist item 7 refuses.
22
+ * `customer_accounts` declares `nonDeactivatable`, so it cannot happen today; the
23
+ * absence of the `catch` is what keeps it fail-closed if that ever changes.
24
+ */
25
+ export function createCustomerEmailResolver(accounts) {
26
+ return async (customerAccountId) => (await accounts.findById(customerAccountId))?.email ?? null;
27
+ }
28
+ /**
29
+ * The language a channel's e-mail is rendered in.
30
+ *
31
+ * A read of the platform's own `SalesChannel` entity through this module's
32
+ * `EntityManager`, which is what both composition roots did and what `orders`
33
+ * does at the identical site — resolving the language for a transactional e-mail
34
+ * (`order-service.ts`, `sendOrderConfirmation`).
35
+ *
36
+ * **Not `salesChannelResolutionPort`**, though the platform contributes it and it
37
+ * carries `defaultLanguage` on its `CachedChannel`. That port is the *cache*, and
38
+ * swapping a direct read for a cached one changes what this answers for a channel
39
+ * written outside the invalidation path — a design decision about channel reads,
40
+ * not a drain's, and T118c moves a value rather than redesigning it. Constitution
41
+ * XII is untouched either way: this resolves no request channel, it reads one
42
+ * attribute of a channel the return case already names.
43
+ *
44
+ * `en-US` for a channel that is not there is the fallback both roots carried.
45
+ */
46
+ export function createChannelLanguageResolver(emFactory) {
47
+ return async (salesChannelId) => (await emFactory().findOne(SalesChannel, { id: salesChannelId }))?.defaultLanguage ?? 'en-US';
48
+ }
49
+ //# sourceMappingURL=notification-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-context.js","sourceRoot":"","sources":["../../../src/backend/services/notification-context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGhE;;;;;;;;;GASG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAmD;IAEnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AAClG,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,6BAA6B,CAC3C,SAA8B;IAE9B,OAAO,KAAK,EAAE,cAAc,EAAE,EAAE,CAC9B,CAAC,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,IAAI,OAAO,CAAC;AAClG,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { ReturnAttachmentDto } from '@endora-commerce/contracts';
3
+ /**
4
+ * ReturnAttachmentService — feature 046 (US1, T027).
5
+ *
6
+ * Links uploaded assets (e.g. defect photos) to a case or a specific case line.
7
+ * The binary upload itself goes through the assets library, which returns an
8
+ * `assetId`; this service persists the `return_case_attachments` link and
9
+ * enforces case ownership.
10
+ */
11
+ export declare class ReturnAttachmentService {
12
+ private readonly emFactory;
13
+ constructor(emFactory: () => EntityManager);
14
+ addToCase(caseId: string, customerAccountId: string, input: {
15
+ assetId: string;
16
+ returnCaseItemId?: string | undefined;
17
+ }): Promise<ReturnAttachmentDto>;
18
+ listForCase(caseId: string): Promise<ReturnAttachmentDto[]>;
19
+ }
20
+ //# sourceMappingURL=return-attachment-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"return-attachment-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/return-attachment-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAKtE;;;;;;;GAOG;AACH,qBAAa,uBAAuB;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,SAAS,CACb,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAChE,OAAO,CAAC,mBAAmB,CAAC;IAezB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;CASlE"}
@@ -0,0 +1,48 @@
1
+ import { ERROR_CODES } from '@endora-commerce/contracts';
2
+ import { HttpError } from '@endora-commerce/platform/http';
3
+ import { ReturnCase } from '../entities/return-case.entity.js';
4
+ import { ReturnCaseAttachment } from '../entities/return-case-attachment.entity.js';
5
+ /**
6
+ * ReturnAttachmentService — feature 046 (US1, T027).
7
+ *
8
+ * Links uploaded assets (e.g. defect photos) to a case or a specific case line.
9
+ * The binary upload itself goes through the assets library, which returns an
10
+ * `assetId`; this service persists the `return_case_attachments` link and
11
+ * enforces case ownership.
12
+ */
13
+ export class ReturnAttachmentService {
14
+ emFactory;
15
+ constructor(emFactory) {
16
+ this.emFactory = emFactory;
17
+ }
18
+ async addToCase(caseId, customerAccountId, input) {
19
+ // command-coverage-ignore: append-only evidence attachment on a case, not an
20
+ // audited domain-state mutation (no before-state, no undo value).
21
+ const em = this.emFactory();
22
+ const rc = await em.findOne(ReturnCase, { id: caseId, customerAccountId });
23
+ if (!rc)
24
+ throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Return case not found.');
25
+ const attachment = em.create(ReturnCaseAttachment, {
26
+ returnCaseId: caseId,
27
+ returnCaseItemId: input.returnCaseItemId ?? null,
28
+ assetId: input.assetId,
29
+ });
30
+ await em.persistAndFlush(attachment);
31
+ return toDto(attachment);
32
+ }
33
+ async listForCase(caseId) {
34
+ const em = this.emFactory();
35
+ const rows = await em.find(ReturnCaseAttachment, { returnCaseId: caseId }, { orderBy: { createdAt: 'asc' } });
36
+ return rows.map(toDto);
37
+ }
38
+ }
39
+ function toDto(a) {
40
+ return {
41
+ id: a.id,
42
+ returnCaseId: a.returnCaseId,
43
+ returnCaseItemId: a.returnCaseItemId ?? null,
44
+ assetId: a.assetId,
45
+ createdAt: a.createdAt.toISOString(),
46
+ };
47
+ }
48
+ //# sourceMappingURL=return-attachment-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"return-attachment-service.js","sourceRoot":"","sources":["../../../src/backend/services/return-attachment-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AAEpF;;;;;;;GAOG;AACH,MAAM,OAAO,uBAAuB;IACL;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,KAAK,CAAC,SAAS,CACb,MAAc,EACd,iBAAyB,EACzB,KAAiE;QAEjE,6EAA6E;QAC7E,kEAAkE;QAClE,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;QAC3E,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,EAAE;YACjD,YAAY,EAAE,MAAM;YACpB,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,IAAI,IAAI;YAChD,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAc;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CACxB,oBAAoB,EACpB,EAAE,YAAY,EAAE,MAAM,EAAE,EACxB,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAClC,CAAC;QACF,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;CACF;AAED,SAAS,KAAK,CAAC,CAAuB;IACpC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,gBAAgB,EAAE,CAAC,CAAC,gBAAgB,IAAI,IAAI;QAC5C,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { ReturnCase } from '../entities/return-case.entity.js';
3
+ import type { ReturnTransitionService } from './return-transition-service.js';
4
+ import type { RmaNumberGenerator } from './rma-number-generator.js';
5
+ import type { ReturnEmailResult } from './return-email-notifier.js';
6
+ /**
7
+ * Best-effort customer notifications on authorize/reject (FR-017).
8
+ *
9
+ * Each answers whether the message went out and, when it did not, why (issue
10
+ * #78). `Promise<void>` said nothing, and this service is the caller that could
11
+ * not tell a delivered notification from a deactivated template.
12
+ */
13
+ export interface ReturnNotifier {
14
+ authorized(rc: ReturnCase): Promise<ReturnEmailResult>;
15
+ rejected(rc: ReturnCase): Promise<ReturnEmailResult>;
16
+ }
17
+ export interface ReturnAuthorizationServiceDeps {
18
+ emFactory: () => EntityManager;
19
+ transitions: ReturnTransitionService;
20
+ rmaGenerator: RmaNumberGenerator;
21
+ notifier?: ReturnNotifier;
22
+ }
23
+ /**
24
+ * ReturnAuthorizationService — feature 046 (US2).
25
+ *
26
+ * Verification outcome handlers: `authorize` assigns a unique RMA number and
27
+ * advances the case to the authorized status; `reject` records a mandatory
28
+ * reason and moves the case to the rejected terminal. Both notify the customer
29
+ * best-effort.
30
+ */
31
+ export declare class ReturnAuthorizationService {
32
+ private readonly deps;
33
+ constructor(deps: ReturnAuthorizationServiceDeps);
34
+ authorize(id: string, adminUserId: string): Promise<{
35
+ rmaNumber: string;
36
+ statusCode: string;
37
+ }>;
38
+ reject(id: string, adminUserId: string, reason: string): Promise<ReturnCase>;
39
+ /**
40
+ * The outer net for a notification that must not undo the transition it
41
+ * announces.
42
+ *
43
+ * The notifier itself now names every non-sent path in its result and writes
44
+ * it to the log (issue #78), so what reaches here is the residue: a throw the
45
+ * notifier deliberately let travel. That includes a `ModuleDisabledError`,
46
+ * which this `catch` still absorbs — re-throwing it would answer 503 to an
47
+ * authorize that has already committed, and the honest repair is an outbox
48
+ * the transition hands the message to, not a rethrow here. What it no longer
49
+ * does is absorb it in silence.
50
+ */
51
+ private notifySafely;
52
+ }
53
+ //# sourceMappingURL=return-authorization-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"return-authorization-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/return-authorization-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAMpE;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,WAAW,EAAE,uBAAuB,CAAC;IACrC,YAAY,EAAE,kBAAkB,CAAC;IACjC,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,qBAAa,0BAA0B;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,8BAA8B;IAE3D,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAkB9F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAsBlF;;;;;;;;;;;OAWG;YACW,YAAY;CAiB3B"}
@@ -0,0 +1,72 @@
1
+ import { ERROR_CODES } from '@endora-commerce/contracts';
2
+ import { HttpError } from '@endora-commerce/platform/http';
3
+ import { RETURN_STATUS_AUTHORIZED, RETURN_STATUS_REJECTED, } from '../domain/return-status-graph.js';
4
+ /**
5
+ * ReturnAuthorizationService — feature 046 (US2).
6
+ *
7
+ * Verification outcome handlers: `authorize` assigns a unique RMA number and
8
+ * advances the case to the authorized status; `reject` records a mandatory
9
+ * reason and moves the case to the rejected terminal. Both notify the customer
10
+ * best-effort.
11
+ */
12
+ export class ReturnAuthorizationService {
13
+ deps;
14
+ constructor(deps) {
15
+ this.deps = deps;
16
+ }
17
+ async authorize(id, adminUserId) {
18
+ const rc = await this.deps.transitions.apply(id, RETURN_STATUS_AUTHORIZED, { kind: 'admin', adminUserId }, {
19
+ mutate: async (target, em) => {
20
+ if (!target.rmaNumber) {
21
+ target.rmaNumber = await this.deps.rmaGenerator.generate(em, target.salesChannelId);
22
+ }
23
+ target.authorizedAt = new Date();
24
+ },
25
+ });
26
+ await this.notifySafely(rc, 'return_authorized', () => this.deps.notifier?.authorized(rc));
27
+ return { rmaNumber: rc.rmaNumber, statusCode: rc.statusCode };
28
+ }
29
+ async reject(id, adminUserId, reason) {
30
+ const trimmed = reason.trim();
31
+ if (!trimmed) {
32
+ throw new HttpError(422, ERROR_CODES.VALIDATION_FAILED, 'A rejection reason is required.', {
33
+ code: 'reason_required',
34
+ });
35
+ }
36
+ const rc = await this.deps.transitions.apply(id, RETURN_STATUS_REJECTED, { kind: 'admin', adminUserId }, {
37
+ reason: trimmed,
38
+ mutate: (target) => {
39
+ target.rejectionReason = trimmed;
40
+ },
41
+ });
42
+ await this.notifySafely(rc, 'return_rejected', () => this.deps.notifier?.rejected(rc));
43
+ return rc;
44
+ }
45
+ /**
46
+ * The outer net for a notification that must not undo the transition it
47
+ * announces.
48
+ *
49
+ * The notifier itself now names every non-sent path in its result and writes
50
+ * it to the log (issue #78), so what reaches here is the residue: a throw the
51
+ * notifier deliberately let travel. That includes a `ModuleDisabledError`,
52
+ * which this `catch` still absorbs — re-throwing it would answer 503 to an
53
+ * authorize that has already committed, and the honest repair is an outbox
54
+ * the transition hands the message to, not a rethrow here. What it no longer
55
+ * does is absorb it in silence.
56
+ */
57
+ async notifySafely(rc, kind, fn) {
58
+ try {
59
+ await fn();
60
+ }
61
+ catch (error) {
62
+ // Notifications are best-effort; never block the workflow transition.
63
+ console.warn('[returns] the return e-mail was not sent', {
64
+ returnCaseId: rc.id,
65
+ kind,
66
+ reason: 'failed',
67
+ error: error instanceof Error ? error.message : error,
68
+ });
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=return-authorization-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"return-authorization-service.js","sourceRoot":"","sources":["../../../src/backend/services/return-authorization-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAK3D,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,kCAAkC,CAAC;AAqB1C;;;;;;;GAOG;AACH,MAAM,OAAO,0BAA0B;IACR;IAA7B,YAA6B,IAAoC;QAApC,SAAI,GAAJ,IAAI,CAAgC;IAAG,CAAC;IAErE,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,WAAmB;QAC7C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAC1C,EAAE,EACF,wBAAwB,EACxB,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,EAC9B;YACE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE;gBAC3B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;oBACtB,MAAM,CAAC,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;gBACtF,CAAC;gBACD,MAAM,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC;YACnC,CAAC;SACF,CACF,CAAC;QACF,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3F,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,SAAU,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,WAAmB,EAAE,MAAc;QAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,iBAAiB,EAAE,iCAAiC,EAAE;gBACzF,IAAI,EAAE,iBAAiB;aACxB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAC1C,EAAE,EACF,sBAAsB,EACtB,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,EAC9B;YACE,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;gBACjB,MAAM,CAAC,eAAe,GAAG,OAAO,CAAC;YACnC,CAAC;SACF,CACF,CAAC;QACF,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;;;;;;;OAWG;IACK,KAAK,CAAC,YAAY,CACxB,EAAc,EACd,IAAY,EACZ,EAAgD;QAEhD,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,CAAC;QACb,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,sEAAsE;YACtE,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE;gBACvD,YAAY,EAAE,EAAE,CAAC,EAAE;gBACnB,IAAI;gBACJ,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { CreateReturnCaseRequest, OrderReturnContextPort, ReturnableResponse, ReturnCaseDetail, ReturnCaseSummary } from '@endora-commerce/contracts';
3
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
4
+ import type { ReturnStatusGraphService } from './return-status-graph-service.js';
5
+ import type { ReturnTransitionService } from './return-transition-service.js';
6
+ export interface ReturnCaseServiceDeps {
7
+ emFactory: () => EntityManager;
8
+ graphService: ReturnStatusGraphService;
9
+ transitions: ReturnTransitionService;
10
+ orderContext: OrderReturnContextPort;
11
+ /** Free-return window in days for a sales channel (0 = no free-return option). */
12
+ resolveFreeReturnDays: (salesChannelId: string) => Promise<number>;
13
+ /** Injected for deterministic tests; defaults to `new Date()`. */
14
+ now?: () => Date;
15
+ /** Feature 054 — audits case creation co-transactionally when provided. */
16
+ auditLog?: AuditPort;
17
+ }
18
+ /**
19
+ * ReturnCaseService — feature 046 (US1).
20
+ *
21
+ * Eligibility evaluation, remaining-returnable computation, and case creation in
22
+ * the initial workflow status. Reads order facts only through the
23
+ * `OrderReturnContextPort` (Principle I).
24
+ */
25
+ export declare class ReturnCaseService {
26
+ private readonly deps;
27
+ constructor(deps: ReturnCaseServiceDeps);
28
+ private now;
29
+ /** Lines a customer may still return for an order, with the eligibility verdict. */
30
+ getReturnable(orderId: string, customerAccountId: string): Promise<ReturnableResponse>;
31
+ /** Open a return/complaint case (FR-001/002/003/005). */
32
+ createCase(input: CreateReturnCaseRequest, customerAccountId: string): Promise<ReturnCaseDetail>;
33
+ listForCustomer(customerAccountId: string): Promise<ReturnCaseSummary[]>;
34
+ getForCustomer(id: string, customerAccountId: string): Promise<ReturnCaseDetail>;
35
+ /** Customer withdraws their own case (if the workflow permits the transition). */
36
+ cancelByCustomer(id: string, customerAccountId: string): Promise<ReturnCaseDetail>;
37
+ /** Detail for the admin surface (includes internal comments). */
38
+ getByIdForAdmin(id: string): Promise<ReturnCaseDetail>;
39
+ private consumedQuantities;
40
+ private isWithinFreeWindow;
41
+ private toSummary;
42
+ private mapDetail;
43
+ }
44
+ //# sourceMappingURL=return-case-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"return-case-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/return-case-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAUlE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AACjF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAK9E,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,YAAY,EAAE,wBAAwB,CAAC;IACvC,WAAW,EAAE,uBAAuB,CAAC;IACrC,YAAY,EAAE,sBAAsB,CAAC;IACrC,kFAAkF;IAClF,qBAAqB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,qBAAqB;IAExD,OAAO,CAAC,GAAG;IAIX,oFAAoF;IAC9E,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA0B5F,yDAAyD;IACnD,UAAU,CACd,KAAK,EAAE,uBAAuB,EAC9B,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,gBAAgB,CAAC;IAmHtB,eAAe,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAWxE,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAOtF,kFAAkF;IAC5E,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAQxF,iEAAiE;IAC3D,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAS9C,kBAAkB;YAalB,kBAAkB;IAQhC,OAAO,CAAC,SAAS;YAcH,SAAS;CAwDxB"}