@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,241 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ import { randomUUID } from 'crypto';
3
+ import { DEFAULT_RETURN_STATUSES, computeDefaultTransitions, } from '../backend/domain/return-status-graph.js';
4
+ import { DEFAULT_RETURN_REASONS } from '../backend/domain/default-reasons.js';
5
+ /**
6
+ * Feature 046 — Returns & Complaints (Refunds, RMA).
7
+ *
8
+ * Creates the returns module schema: the RMA case + items, the configurable
9
+ * status graph (`return_statuses` + `return_status_transitions`) seeded from the
10
+ * single source of truth in `domain/return-status-graph.ts`, comments, managed
11
+ * reasons (seeded with defaults), return delivery methods, refunds, return
12
+ * shipments, attachments, saved views, and the `return_cases_rma_seq` sequence.
13
+ */
14
+ export class Migration20260625T144227ReturnsInit extends Migration {
15
+ async up() {
16
+ // --- Configurable status graph -----------------------------------------
17
+ this.addSql(`
18
+ create table "return_statuses" (
19
+ "id" uuid not null,
20
+ "code" varchar(64) not null,
21
+ "name" jsonb not null,
22
+ "default_name" varchar(120) not null,
23
+ "is_initial" boolean not null default false,
24
+ "is_terminal" boolean not null default false,
25
+ "is_system" boolean not null default false,
26
+ "weight" int not null default 100,
27
+ "color" varchar(16) not null default '#64748b',
28
+ "created_at" timestamptz not null,
29
+ "updated_at" timestamptz not null,
30
+ constraint "return_statuses_pkey" primary key ("id")
31
+ );
32
+ `);
33
+ this.addSql(`alter table "return_statuses" add constraint "return_statuses_code_unique" unique ("code");`);
34
+ this.addSql(`
35
+ create table "return_status_transitions" (
36
+ "id" uuid not null,
37
+ "from_status_code" varchar(64) not null,
38
+ "to_status_code" varchar(64) not null,
39
+ "is_system" boolean not null default false,
40
+ "created_at" timestamptz not null,
41
+ constraint "return_status_transitions_pkey" primary key ("id")
42
+ );
43
+ `);
44
+ this.addSql(`alter table "return_status_transitions" add constraint "return_status_transitions_pair_unique" unique ("from_status_code", "to_status_code");`);
45
+ this.addSql(`create index "return_status_transitions_from_idx" on "return_status_transitions" ("from_status_code");`);
46
+ for (const s of DEFAULT_RETURN_STATUSES) {
47
+ this.addSql(`insert into "return_statuses" ("id", "code", "name", "default_name", "is_initial", "is_terminal", "is_system", "weight", "color", "created_at", "updated_at") ` +
48
+ `values ('${randomUUID()}', '${s.code}', '${jsonLiteral(s.name)}'::jsonb, '${s.defaultName}', ${s.isInitial}, ${s.isTerminal}, ${s.isSystem}, ${s.weight}, '${s.color}', now(), now());`);
49
+ }
50
+ for (const t of computeDefaultTransitions()) {
51
+ this.addSql(`insert into "return_status_transitions" ("id", "from_status_code", "to_status_code", "is_system", "created_at") ` +
52
+ `values ('${randomUUID()}', '${t.fromStatusCode}', '${t.toStatusCode}', ${t.isSystem}, now());`);
53
+ }
54
+ // --- RMA case number sequence ------------------------------------------
55
+ this.addSql(`create sequence if not exists "return_cases_rma_seq";`);
56
+ // --- Cases & items ------------------------------------------------------
57
+ this.addSql(`
58
+ create table "return_cases" (
59
+ "id" uuid not null,
60
+ "kind" varchar(16) not null,
61
+ "rma_number" varchar(64) null,
62
+ "order_id" uuid not null,
63
+ "sales_channel_id" uuid not null,
64
+ "customer_account_id" uuid not null,
65
+ "organization_id" uuid null,
66
+ "status_code" varchar(64) not null,
67
+ "currency" varchar(3) not null,
68
+ "return_delivery_method_id" uuid null,
69
+ "applied_return_cost" numeric(14,2) not null default 0,
70
+ "return_cost_bearer" varchar(16) not null default 'customer',
71
+ "free_return_eligible" boolean not null default false,
72
+ "resolution_type" varchar(16) null,
73
+ "refund_payment_method_id" uuid null,
74
+ "total_refund_amount" numeric(14,2) not null default 0,
75
+ "rejection_reason" text null,
76
+ "submitted_at" timestamptz not null,
77
+ "authorized_at" timestamptz null,
78
+ "resolved_at" timestamptz null,
79
+ "closed_at" timestamptz null,
80
+ "created_at" timestamptz not null,
81
+ "updated_at" timestamptz not null,
82
+ constraint "return_cases_pkey" primary key ("id")
83
+ );
84
+ `);
85
+ this.addSql(`alter table "return_cases" add constraint "return_cases_rma_number_unique" unique ("rma_number");`);
86
+ this.addSql(`create index "return_cases_order_idx" on "return_cases" ("order_id");`);
87
+ this.addSql(`create index "return_cases_sales_channel_idx" on "return_cases" ("sales_channel_id");`);
88
+ this.addSql(`create index "return_cases_customer_idx" on "return_cases" ("customer_account_id");`);
89
+ this.addSql(`create index "return_cases_organization_idx" on "return_cases" ("organization_id");`);
90
+ this.addSql(`create index "return_cases_status_idx" on "return_cases" ("status_code");`);
91
+ this.addSql(`
92
+ create table "return_case_items" (
93
+ "id" uuid not null,
94
+ "return_case_id" uuid not null,
95
+ "order_item_id" uuid not null,
96
+ "product_id" uuid not null,
97
+ "product_name" varchar(512) not null,
98
+ "quantity" int not null,
99
+ "reason_id" uuid null,
100
+ "description" text null,
101
+ "inspection_outcome" varchar(16) null,
102
+ "default_refund_amount" numeric(14,2) not null,
103
+ "approved_refund_amount" numeric(14,2) not null default 0,
104
+ constraint "return_case_items_pkey" primary key ("id")
105
+ );
106
+ `);
107
+ this.addSql(`create index "return_case_items_case_idx" on "return_case_items" ("return_case_id");`);
108
+ this.addSql(`create index "return_case_items_order_item_idx" on "return_case_items" ("order_item_id");`);
109
+ // --- Comments -----------------------------------------------------------
110
+ this.addSql(`
111
+ create table "return_case_comments" (
112
+ "id" uuid not null,
113
+ "return_case_id" uuid not null,
114
+ "author_admin_user_id" uuid null,
115
+ "author_customer_account_id" uuid null,
116
+ "body" text not null,
117
+ "is_customer_visible" boolean not null default true,
118
+ "notify_customer" boolean not null default false,
119
+ "created_at" timestamptz not null,
120
+ constraint "return_case_comments_pkey" primary key ("id")
121
+ );
122
+ `);
123
+ this.addSql(`create index "return_case_comments_case_idx" on "return_case_comments" ("return_case_id");`);
124
+ this.addSql(`create index "return_case_comments_created_idx" on "return_case_comments" ("created_at");`);
125
+ // --- Reasons (seeded with defaults) ------------------------------------
126
+ this.addSql(`
127
+ create table "return_reasons" (
128
+ "id" uuid not null,
129
+ "label" jsonb not null,
130
+ "applies_to" varchar(16) not null,
131
+ "is_active" boolean not null default true,
132
+ "weight" int not null default 100,
133
+ "created_at" timestamptz not null,
134
+ "updated_at" timestamptz not null,
135
+ constraint "return_reasons_pkey" primary key ("id")
136
+ );
137
+ `);
138
+ for (const r of DEFAULT_RETURN_REASONS) {
139
+ this.addSql(`insert into "return_reasons" ("id", "label", "applies_to", "is_active", "weight", "created_at", "updated_at") ` +
140
+ `values ('${randomUUID()}', '${jsonLiteral(r.label)}'::jsonb, '${r.appliesTo}', true, ${r.weight}, now(), now());`);
141
+ }
142
+ // --- Return delivery methods -------------------------------------------
143
+ this.addSql(`
144
+ create table "return_delivery_methods" (
145
+ "id" uuid not null,
146
+ "delivery_method_id" uuid not null,
147
+ "return_cost" numeric(14,2) not null,
148
+ "currency" varchar(3) not null,
149
+ "is_active" boolean not null default true,
150
+ "created_at" timestamptz not null,
151
+ "updated_at" timestamptz not null,
152
+ constraint "return_delivery_methods_pkey" primary key ("id")
153
+ );
154
+ `);
155
+ this.addSql(`create index "return_delivery_methods_method_idx" on "return_delivery_methods" ("delivery_method_id");`);
156
+ // --- Refunds ------------------------------------------------------------
157
+ this.addSql(`
158
+ create table "refunds" (
159
+ "id" uuid not null,
160
+ "return_case_id" uuid not null,
161
+ "resolution_type" varchar(16) not null,
162
+ "amount" numeric(14,2) not null,
163
+ "currency" varchar(3) not null,
164
+ "payment_method_id" uuid null,
165
+ "settlement_state" varchar(16) not null,
166
+ "external_reference" varchar(128) null,
167
+ "provider_details" jsonb null,
168
+ "failure_reason" text null,
169
+ "corrective_invoice_id" uuid null,
170
+ "credit_limit_topup_applied" boolean not null default false,
171
+ "attempt_no" int not null default 1,
172
+ "created_at" timestamptz not null,
173
+ "updated_at" timestamptz not null,
174
+ constraint "refunds_pkey" primary key ("id")
175
+ );
176
+ `);
177
+ this.addSql(`create index "refunds_case_idx" on "refunds" ("return_case_id");`);
178
+ // --- Return shipments ---------------------------------------------------
179
+ this.addSql(`
180
+ create table "return_shipments" (
181
+ "id" uuid not null,
182
+ "return_case_id" uuid not null,
183
+ "direction" varchar(16) not null,
184
+ "delivery_method_id" uuid null,
185
+ "external_reference" varchar(128) null,
186
+ "status" varchar(16) not null default 'pending',
187
+ "created_at" timestamptz not null,
188
+ "updated_at" timestamptz not null,
189
+ constraint "return_shipments_pkey" primary key ("id")
190
+ );
191
+ `);
192
+ this.addSql(`create index "return_shipments_case_idx" on "return_shipments" ("return_case_id");`);
193
+ // --- Attachments --------------------------------------------------------
194
+ this.addSql(`
195
+ create table "return_case_attachments" (
196
+ "id" uuid not null,
197
+ "return_case_id" uuid not null,
198
+ "return_case_item_id" uuid null,
199
+ "asset_id" uuid not null,
200
+ "created_at" timestamptz not null,
201
+ constraint "return_case_attachments_pkey" primary key ("id")
202
+ );
203
+ `);
204
+ this.addSql(`create index "return_case_attachments_case_idx" on "return_case_attachments" ("return_case_id");`);
205
+ // --- Saved views --------------------------------------------------------
206
+ this.addSql(`
207
+ create table "return_list_saved_views" (
208
+ "id" uuid not null,
209
+ "owner_admin_user_id" uuid not null,
210
+ "name" varchar(200) not null,
211
+ "shared" boolean not null default false,
212
+ "filters" jsonb not null,
213
+ "sort" jsonb not null,
214
+ "visible_columns" jsonb null,
215
+ "created_at" timestamptz not null,
216
+ "updated_at" timestamptz not null,
217
+ constraint "return_list_saved_views_pkey" primary key ("id")
218
+ );
219
+ `);
220
+ this.addSql(`create index "return_list_saved_views_owner_idx" on "return_list_saved_views" ("owner_admin_user_id");`);
221
+ }
222
+ async down() {
223
+ this.addSql(`drop table if exists "return_list_saved_views";`);
224
+ this.addSql(`drop table if exists "return_case_attachments";`);
225
+ this.addSql(`drop table if exists "return_shipments";`);
226
+ this.addSql(`drop table if exists "refunds";`);
227
+ this.addSql(`drop table if exists "return_delivery_methods";`);
228
+ this.addSql(`drop table if exists "return_reasons";`);
229
+ this.addSql(`drop table if exists "return_case_comments";`);
230
+ this.addSql(`drop table if exists "return_case_items";`);
231
+ this.addSql(`drop table if exists "return_cases";`);
232
+ this.addSql(`drop sequence if exists "return_cases_rma_seq";`);
233
+ this.addSql(`drop table if exists "return_status_transitions";`);
234
+ this.addSql(`drop table if exists "return_statuses";`);
235
+ }
236
+ }
237
+ /** Serialize a localized label map to a single-quoted SQL JSON literal. */
238
+ function jsonLiteral(value) {
239
+ return JSON.stringify(value).replace(/'/g, "''");
240
+ }
241
+ //# sourceMappingURL=20260625T144227_returns_init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260625T144227_returns_init.js","sourceRoot":"","sources":["../../src/migrations/20260625T144227_returns_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EACL,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAE9E;;;;;;;;GAQG;AACH,MAAM,OAAO,mCAAoC,SAAQ,SAAS;IACvD,KAAK,CAAC,EAAE;QACf,0EAA0E;QAC1E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;KAeX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,6FAA6F,CAAC,CAAC;QAE3G,IAAI,CAAC,MAAM,CAAC;;;;;;;;;KASX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,+IAA+I,CAChJ,CAAC;QACF,IAAI,CAAC,MAAM,CACT,wGAAwG,CACzG,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,uBAAuB,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CACT,gKAAgK;gBAC9J,YAAY,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,OAAO,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,WAAW,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,mBAAmB,CAC3L,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,yBAAyB,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CACT,kHAAkH;gBAChH,YAAY,UAAU,EAAE,OAAO,CAAC,CAAC,cAAc,OAAO,CAAC,CAAC,YAAY,MAAM,CAAC,CAAC,QAAQ,WAAW,CAClG,CAAC;QACJ,CAAC;QAED,0EAA0E;QAC1E,IAAI,CAAC,MAAM,CAAC,uDAAuD,CAAC,CAAC;QAErE,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,mGAAmG,CAAC,CAAC;QACjH,IAAI,CAAC,MAAM,CAAC,uEAAuE,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,CAAC,uFAAuF,CAAC,CAAC;QACrG,IAAI,CAAC,MAAM,CAAC,qFAAqF,CAAC,CAAC;QACnG,IAAI,CAAC,MAAM,CAAC,qFAAqF,CAAC,CAAC;QACnG,IAAI,CAAC,MAAM,CAAC,2EAA2E,CAAC,CAAC;QAEzF,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;KAeX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,sFAAsF,CAAC,CAAC;QACpG,IAAI,CAAC,MAAM,CAAC,2FAA2F,CAAC,CAAC;QAEzG,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;KAYX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,4FAA4F,CAAC,CAAC;QAC1G,IAAI,CAAC,MAAM,CAAC,2FAA2F,CAAC,CAAC;QAEzG,0EAA0E;QAC1E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;KAWX,CAAC,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC;YACvC,IAAI,CAAC,MAAM,CACT,gHAAgH;gBAC9G,YAAY,UAAU,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,SAAS,YAAY,CAAC,CAAC,MAAM,kBAAkB,CACrH,CAAC;QACJ,CAAC;QAED,0EAA0E;QAC1E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;KAWX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,wGAAwG,CACzG,CAAC;QAEF,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;KAmBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,kEAAkE,CAAC,CAAC;QAEhF,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;KAYX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,oFAAoF,CAAC,CAAC;QAElG,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;KASX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,kGAAkG,CAAC,CAAC;QAEhH,2EAA2E;QAC3E,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAaX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,wGAAwG,CACzG,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,0CAA0C,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,CAAC,iCAAiC,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,8CAA8C,CAAC,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,sCAAsC,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,mDAAmD,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;IACzD,CAAC;CACF;AAED,2EAA2E;AAC3E,SAAS,WAAW,CAAC,KAA6B;IAChD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * `refunds.corrective_invoice_outcome` — the three-way answer, persisted
4
+ * (D-92, issue #156).
5
+ *
6
+ * The row held `corrective_invoice_id` alone, so `null` stood for "no
7
+ * correction was due", "none was asked for" and "one was asked for and we do
8
+ * not know" at once. The distinction lived in the settlement response and the
9
+ * audit entry, neither of which survives a page reload — which is exactly the
10
+ * confusion the explicit `reason` field was added to prevent (#135).
11
+ *
12
+ * `not_requested` is the default because it is what a row with no correction
13
+ * asked for means, and the backfill promotes the rows that carry a document.
14
+ * `corrective_invoice_id` stays, and stays non-null exactly when the outcome is
15
+ * `issued`.
16
+ *
17
+ * The pre-D-92 rows with no document are backfilled to `not_requested` rather
18
+ * than `not_due`: which of the two they were is not recoverable from the row,
19
+ * and claiming the more specific answer would invent it.
20
+ */
21
+ export declare class Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome extends Migration {
22
+ up(): Promise<void>;
23
+ down(): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=20260817T203206_returns_refund_corrective_invoice_outcome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260817T203206_returns_refund_corrective_invoice_outcome.d.ts","sourceRoot":"","sources":["../../src/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,6DAA8D,SAAQ,SAAS;IAC3E,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAOrC"}
@@ -0,0 +1,46 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * `refunds.corrective_invoice_outcome` — the three-way answer, persisted
4
+ * (D-92, issue #156).
5
+ *
6
+ * The row held `corrective_invoice_id` alone, so `null` stood for "no
7
+ * correction was due", "none was asked for" and "one was asked for and we do
8
+ * not know" at once. The distinction lived in the settlement response and the
9
+ * audit entry, neither of which survives a page reload — which is exactly the
10
+ * confusion the explicit `reason` field was added to prevent (#135).
11
+ *
12
+ * `not_requested` is the default because it is what a row with no correction
13
+ * asked for means, and the backfill promotes the rows that carry a document.
14
+ * `corrective_invoice_id` stays, and stays non-null exactly when the outcome is
15
+ * `issued`.
16
+ *
17
+ * The pre-D-92 rows with no document are backfilled to `not_requested` rather
18
+ * than `not_due`: which of the two they were is not recoverable from the row,
19
+ * and claiming the more specific answer would invent it.
20
+ */
21
+ export class Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome extends Migration {
22
+ async up() {
23
+ this.addSql(`
24
+ alter table "refunds"
25
+ add column "corrective_invoice_outcome" varchar(16) not null default 'not_requested';
26
+ `);
27
+ this.addSql(`
28
+ alter table "refunds"
29
+ add constraint "refunds_corrective_invoice_outcome_check"
30
+ check ("corrective_invoice_outcome" in ('issued', 'not_due', 'not_requested'));
31
+ `);
32
+ this.addSql(`
33
+ update "refunds"
34
+ set "corrective_invoice_outcome" = 'issued'
35
+ where "corrective_invoice_id" is not null;
36
+ `);
37
+ }
38
+ async down() {
39
+ this.addSql(`
40
+ alter table "refunds"
41
+ drop constraint if exists "refunds_corrective_invoice_outcome_check";
42
+ `);
43
+ this.addSql(`alter table "refunds" drop column if exists "corrective_invoice_outcome";`);
44
+ }
45
+ }
46
+ //# sourceMappingURL=20260817T203206_returns_refund_corrective_invoice_outcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260817T203206_returns_refund_corrective_invoice_outcome.js","sourceRoot":"","sources":["../../src/migrations/20260817T203206_returns_refund_corrective_invoice_outcome.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,6DAA8D,SAAQ,SAAS;IACjF,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;KAGX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;KAIX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;KAIX,CAAC,CAAC;IACL,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC;;;KAGX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which is the order of this module's own
10
+ * migrations and of nothing else (feature 081): a manifest `dependencies` array
11
+ * is the only thing ordering this block against another module's.
12
+ *
13
+ * The **named** exports stay beside the array, and the asymmetry with
14
+ * `./backend` — which publishes an array and no named class (D-168) — is
15
+ * deliberate. `db/migrations-registry.generated.ts` imports each class by name
16
+ * from this specifier, and a migration class name is contract in a way an entity
17
+ * class name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom is
22
+ * a query against a table nobody created.
23
+ */
24
+ import { Migration20260625T144227ReturnsInit } from './20260625T144227_returns_init.js';
25
+ import { Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome } from './20260817T203206_returns_refund_corrective_invoice_outcome.js';
26
+ export declare const migrations: (typeof Migration20260625T144227ReturnsInit)[];
27
+ export { Migration20260625T144227ReturnsInit, Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome, };
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,mCAAmC,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,6DAA6D,EAAE,MAAM,gEAAgE,CAAC;AAE/I,eAAO,MAAM,UAAU,gDAGtB,CAAC;AAEF,OAAO,EACL,mCAAmC,EACnC,6DAA6D,GAC9D,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which is the order of this module's own
10
+ * migrations and of nothing else (feature 081): a manifest `dependencies` array
11
+ * is the only thing ordering this block against another module's.
12
+ *
13
+ * The **named** exports stay beside the array, and the asymmetry with
14
+ * `./backend` — which publishes an array and no named class (D-168) — is
15
+ * deliberate. `db/migrations-registry.generated.ts` imports each class by name
16
+ * from this specifier, and a migration class name is contract in a way an entity
17
+ * class name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom is
22
+ * a query against a table nobody created.
23
+ */
24
+ import { Migration20260625T144227ReturnsInit } from './20260625T144227_returns_init.js';
25
+ import { Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome } from './20260817T203206_returns_refund_corrective_invoice_outcome.js';
26
+ export const migrations = [
27
+ Migration20260625T144227ReturnsInit,
28
+ Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome,
29
+ ];
30
+ export { Migration20260625T144227ReturnsInit, Migration20260817T203206ReturnsRefundCorrectiveInvoiceOutcome, };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,mCAAmC,EAAE,MAAM,mCAAmC,CAAC;AACxF,OAAO,EAAE,6DAA6D,EAAE,MAAM,gEAAgE,CAAC;AAE/I,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,mCAAmC;IACnC,6DAA6D;CAC9D,CAAC;AAEF,OAAO,EACL,mCAAmC,EACnC,6DAA6D,GAC9D,CAAC"}
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: returns
3
+ description: Returns and complaints (RMA) — submission, verification, reverse-logistics shipments and settlement over a configurable status graph
4
+ ---
5
+
6
+ # `returns`
7
+
8
+ Returns & complaints (Refunds, RMA). Manages the lifecycle of a return or
9
+ complaint case raised against a completed order — submission, verification and
10
+ RMA-number assignment, reverse-logistics shipments, and settlement (money
11
+ refund, store credit, replacement, or repair) including the corrective invoice.
12
+ Mirrors the `orders` module's configurable status-graph workflow.
13
+
14
+ ## Public surface
15
+
16
+ Admin routes are gated by `returns:read` (read) / `returns:write` (mutations).
17
+
18
+ | Verb + Path | Audience | Purpose |
19
+ | --- | --- | --- |
20
+ | `GET /api/v1/orders/:orderId/returnable` | customer | Returnable lines + eligibility for an order |
21
+ | `POST /api/v1/returns` | customer | Open a return/complaint case |
22
+ | `GET /api/v1/returns` | customer | List the caller's cases |
23
+ | `GET /api/v1/returns/:id` | customer | Case detail (customer-visible comments only) |
24
+ | `POST /api/v1/returns/:id/comments` | customer | Reply on a case |
25
+ | `POST /api/v1/returns/:id/select-delivery-method` | customer | Choose a return delivery method |
26
+ | `POST /api/v1/returns/:id/cancel` | customer | Withdraw the case |
27
+ | `GET /api/v1/returns/reasons` | customer | Active reasons for the storefront form |
28
+ | `GET /api/v1/admin/returns` | admin | List/filter/search cases + per-status counts |
29
+ | `GET /api/v1/admin/returns/export` | admin | CSV export of the current view |
30
+ | `POST /api/v1/admin/returns/bulk-transition` | admin | Bulk status change (skips disallowed) |
31
+ | `GET /api/v1/admin/returns/:id` | admin | Case detail (incl. internal comments) |
32
+ | `POST /api/v1/admin/returns/:id/authorize` | admin | Assign RMA number, advance to `authorized` |
33
+ | `POST /api/v1/admin/returns/:id/reject` | admin | Reject with a mandatory reason |
34
+ | `POST /api/v1/admin/returns/:id/transition` | admin | Guarded status transition |
35
+ | `GET\|POST /api/v1/admin/returns/:id/settlement` | admin | Prefill / execute settlement |
36
+ | `GET\|POST /api/v1/admin/returns/:id/comments` | admin | List / add comment (visibility + notify) |
37
+ | `GET\|POST /api/v1/admin/returns/:id/shipments` + `/:shipmentId/receive` | admin | Return shipments |
38
+ | `…/statuses`, `…/transitions`, `…/reasons`, `…/delivery-methods`, `…/list-views` | admin | Configuration + saved views |
39
+
40
+ ## Status machine (configurable)
41
+
42
+ The case lifecycle is **admin-configurable** (`return_statuses` +
43
+ `return_status_transitions`, seeded on install). Defaults:
44
+
45
+ - **new** (initial) → **authorized** → **received** → **resolved** → **closed** (terminal)
46
+ - **rejected** (terminal) reachable from new/authorized/received; **cancelled** (terminal) from new/authorized.
47
+
48
+ Transitions are enforced; the initial status is immutable; terminal statuses
49
+ have no outgoing edges. Each transition emits templated `return.status.*`
50
+ before/after events and is written to the audit log.
51
+
52
+ ## Key behaviours
53
+
54
+ - **Eligibility & free-return window** — a case is allowed once the order
55
+ reaches its fulfilment-completing status; the free-return window
56
+ (`returns.free_return_days`, default **14** per EU Directive (EU) 2023/2673)
57
+ is counted from that moment and governs who bears the return shipping cost.
58
+ - **RMA numbering** — `${prefix}${sequence}${suffix}` from
59
+ `returns.rma_number_prefix` / `returns.rma_number_suffix`, assigned on
60
+ authorization, unique and never reused.
61
+ - **Partial / repeat returns** — per-line quantity up to the remaining
62
+ returnable amount, excluding quantities already covered by non-rejected /
63
+ non-cancelled cases.
64
+ - **Settlement** — per-line refund defaults to the amount paid for the returned
65
+ quantity and may never exceed it. Resolutions: refund (money), credit (tops up
66
+ the organization's `credit_limits` grant), replacement, or repair. A corrective
67
+ invoice (`invoices` kind `correction`) is requested for money/credit settlements.
68
+ An order that was never invoiced has no VAT document to correct, so none is
69
+ issued: the settlement succeeds, the refund is recorded on the return case and
70
+ the payment record, and the result states `correctiveInvoice: { issued: false,
71
+ reason: "order_not_invoiced" }`.
72
+ - **A switched-off payment gateway refuses the settlement**.
73
+ Money resolutions on a gateway-paid order call the PSP module that took the
74
+ payment; when an operator has that module switched off — or the deployment
75
+ does not offer it — the settlement answers `503 MODULE_DISABLED` naming the
76
+ module, with `Retry-After`. Nothing moves: the case keeps its status, no
77
+ `refunds` row is written, no corrective invoice is issued and no customer
78
+ e-mail goes out. Switching the module back on is the whole remedy. This is
79
+ distinct from a deployment that has **no** PSP refund integration at all,
80
+ which still settles as `pending_manual` for a person to pay out by hand —
81
+ there is nothing there to switch on.
82
+
83
+ ## Cross-module interfaces
84
+
85
+ The module reads/affects other domains only through documented ports, never
86
+ internal imports:
87
+
88
+ - `OrderReturnContextPort` (orders) — paid-per-line amounts + completing-status time.
89
+ - `PaymentRefundPort` (payments) — issue the refund, answer `pending_manual`
90
+ where no PSP integration exists, or refuse when the gateway that took the
91
+ payment is switched off.
92
+ - `CorrectiveInvoicePort` (invoices) — create a `correction` invoice, or answer
93
+ that none is due because the order carries no invoice to correct.
94
+ - `CreditTopupPort` (credit_limits) — credit the organization grant.
95
+ - `ShipmentService` (shipments) — optional replacement outbound shipment.
96
+
97
+ ## Schema
98
+
99
+ Migration `080_returns_init.ts` creates `return_cases`, `return_case_items`,
100
+ `return_case_comments`, `return_statuses`, `return_status_transitions`,
101
+ `return_reasons`, `return_delivery_methods`, `refunds`, `return_shipments`,
102
+ `return_case_attachments`, `return_list_saved_views`, and the
103
+ `return_cases_rma_seq` sequence.
package/i18n/en.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "settings.freeReturnDays.label": "Free-return window (days)",
3
+ "settings.rmaNumberPrefix.label": "RMA number prefix",
4
+ "settings.rmaNumberSuffix.label": "RMA number suffix",
5
+ "settings.defaultCostBearerOutsideWindow.label": "Return cost bearer outside the free-return window",
6
+ "actions.openReturns.label": "Open returns",
7
+ "actions.openReturns.description": "View and manage returns and complaints (RMA)",
8
+ "actions.returnStatusConfig.label": "Return statuses",
9
+ "actions.returnStatusConfig.description": "Configure the return/complaint status lifecycle and transitions",
10
+ "list.title": "Returns",
11
+ "list.search.placeholder": "Search by RMA number, order, customer",
12
+ "statusConfig.title": "Return status configuration",
13
+ "statusConfig.addStatus": "Add status",
14
+ "statusConfig.terminal": "Terminal status",
15
+ "statusConfig.initial": "Initial status",
16
+ "statusConfig.deleteInUse": "Cannot delete a status that cases currently use",
17
+ "statusConfig.cannotDeleteInitial": "The initial status cannot be deleted",
18
+ "comments.add": "Add comment",
19
+ "comments.internal": "Internal (admin only)",
20
+ "comments.customerVisible": "Visible to customer",
21
+ "comments.notifyCustomer": "Notify customer",
22
+ "comments.closedTerminal": "Commenting is closed for finished cases",
23
+ "settlement.refund": "Refund money",
24
+ "settlement.credit": "Credit toward future orders",
25
+ "settlement.replacement": "Replacement",
26
+ "settlement.repair": "Repair",
27
+ "nav.returns.label": "Returns"
28
+ }
package/i18n/pl.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "settings.freeReturnDays.label": "Okno bezpłatnego zwrotu (dni)",
3
+ "settings.rmaNumberPrefix.label": "Prefiks numeru RMA",
4
+ "settings.rmaNumberSuffix.label": "Sufiks numeru RMA",
5
+ "settings.defaultCostBearerOutsideWindow.label": "Strona ponosząca koszt zwrotu po upływie okna",
6
+ "actions.openReturns.label": "Otwórz zwroty",
7
+ "actions.openReturns.description": "Przeglądaj i zarządzaj zwrotami i reklamacjami (RMA)",
8
+ "actions.returnStatusConfig.label": "Statusy zwrotów",
9
+ "actions.returnStatusConfig.description": "Konfiguruj cykl życia i przejścia statusów zwrotu/reklamacji",
10
+ "list.title": "Zwroty",
11
+ "list.search.placeholder": "Szukaj po numerze RMA, zamówieniu, kliencie",
12
+ "statusConfig.title": "Konfiguracja statusów zwrotu",
13
+ "statusConfig.addStatus": "Dodaj status",
14
+ "statusConfig.terminal": "Status końcowy",
15
+ "statusConfig.initial": "Status początkowy",
16
+ "statusConfig.deleteInUse": "Nie można usunąć statusu używanego przez sprawy",
17
+ "statusConfig.cannotDeleteInitial": "Nie można usunąć statusu początkowego",
18
+ "comments.add": "Dodaj komentarz",
19
+ "comments.internal": "Wewnętrzny (tylko admin)",
20
+ "comments.customerVisible": "Widoczny dla klienta",
21
+ "comments.notifyCustomer": "Powiadom klienta",
22
+ "comments.closedTerminal": "Komentowanie jest zamknięte dla zakończonych spraw",
23
+ "settlement.refund": "Zwrot pieniędzy",
24
+ "settlement.credit": "Zaliczenie na poczet przyszłych zamówień",
25
+ "settlement.replacement": "Wymiana",
26
+ "settlement.repair": "Naprawa",
27
+ "nav.returns.label": "Zwroty"
28
+ }