medusajs-documents-plugin 0.0.0-stage → 1.1.2

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 (41) hide show
  1. package/.medusa/server/src/admin/index.js +2441 -0
  2. package/.medusa/server/src/admin/index.mjs +2442 -0
  3. package/.medusa/server/src/api/admin/documents/[id]/document/route.js +36 -0
  4. package/.medusa/server/src/api/admin/documents/[id]/send/route.js +41 -0
  5. package/.medusa/server/src/api/admin/documents/[id]/sync-zoho/route.js +68 -0
  6. package/.medusa/server/src/api/admin/documents/custom/route.js +48 -0
  7. package/.medusa/server/src/api/admin/documents/manual/route.js +46 -0
  8. package/.medusa/server/src/api/admin/documents/route.js +36 -0
  9. package/.medusa/server/src/api/admin/documents/settings/route.js +44 -0
  10. package/.medusa/server/src/api/admin/documents/templates/preview/route.js +159 -0
  11. package/.medusa/server/src/api/admin/documents/zoho/list/route.js +51 -0
  12. package/.medusa/server/src/api/documents/[id]/document/route.js +36 -0
  13. package/.medusa/server/src/api/documents/r/[code]/route.js +29 -0
  14. package/.medusa/server/src/api/documents/templates/preview/route.js +159 -0
  15. package/.medusa/server/src/api/store/documents/r/[code]/route.js +22 -0
  16. package/.medusa/server/src/index.js +27 -0
  17. package/.medusa/server/src/modules/documents/index.js +13 -0
  18. package/.medusa/server/src/modules/documents/migrations/Migration20261012164601.js +23 -0
  19. package/.medusa/server/src/modules/documents/migrations/Migration20261014150000.js +20 -0
  20. package/.medusa/server/src/modules/documents/migrations/Migration20261015160000.js +46 -0
  21. package/.medusa/server/src/modules/documents/models/document-link.js +12 -0
  22. package/.medusa/server/src/modules/documents/models/document-record.js +33 -0
  23. package/.medusa/server/src/modules/documents/models/document-settings.js +79 -0
  24. package/.medusa/server/src/modules/documents/service.js +587 -0
  25. package/.medusa/server/src/services/notification-sender.js +612 -0
  26. package/.medusa/server/src/services/order-notification-templates.js +510 -0
  27. package/.medusa/server/src/services/pdf-post-processor.js +64 -0
  28. package/.medusa/server/src/services/pdfkit-generator.js +438 -0
  29. package/.medusa/server/src/services/zoho-books.js +221 -0
  30. package/.medusa/server/src/subscribers/order-documents.js +424 -0
  31. package/.medusa/server/src/subscribers/repair-documents.js +216 -0
  32. package/.medusa/server/src/utils/integrate.js +37 -0
  33. package/.medusa/server/src/utils/payment-link.js +69 -0
  34. package/.medusa/server/src/workflows/create-manual-document.js +27 -0
  35. package/.medusa/server/src/workflows/generate-document.js +24 -0
  36. package/.medusa/server/src/workflows/index.js +20 -0
  37. package/.medusa/server/src/workflows/send-document-notification.js +41 -0
  38. package/CHANGELOG.md +87 -0
  39. package/LICENSE +21 -0
  40. package/README.md +201 -2
  41. package/package.json +86 -4
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.config = void 0;
4
+ exports.default = repairDocumentsSubscriber;
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const documents_1 = require("../modules/documents");
7
+ const payment_link_1 = require("../utils/payment-link");
8
+ async function repairDocumentsSubscriber({ event, container, }) {
9
+ const logger = container.resolve("logger");
10
+ const eventName = event.name;
11
+ const data = event.data;
12
+ logger.info(`[Documents-Subscriber] Handling repair event '${eventName}'`);
13
+ try {
14
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE, {
15
+ allowUnregistered: true,
16
+ });
17
+ if (!documentService)
18
+ return;
19
+ const settings = await documentService.getSettings();
20
+ // Fix 5: Handle repair completion via repair.status_changed where status === "completed"
21
+ const isCompleted = eventName === "repair.completed" ||
22
+ (eventName === "repair.status_changed" &&
23
+ (data.status === "completed" || data.status === "repaired"));
24
+ // Check on/off toggles
25
+ if (isCompleted) {
26
+ if (!settings.event_repair_completed_enabled) {
27
+ logger.info(`[Documents-Subscriber] Repair completed document processing is disabled in settings.`);
28
+ return;
29
+ }
30
+ }
31
+ else if (eventName === "repair.status_changed") {
32
+ if (!settings.event_repair_status_changed_enabled)
33
+ return;
34
+ }
35
+ if (eventName === "repair.ticket.compliance_requested" && !settings.event_repair_compliance_enabled)
36
+ return;
37
+ if (eventName === "repair.created" && !settings.event_repair_created_enabled)
38
+ return;
39
+ if (eventName === "repair.customer_reminder" && !settings.event_repair_reminder_enabled)
40
+ return;
41
+ const ticketId = data.id || data.repair_ticket_id;
42
+ if (!ticketId)
43
+ return;
44
+ const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
45
+ const { data: tickets } = await query
46
+ .graph({
47
+ entity: "repair_ticket",
48
+ fields: [
49
+ "*",
50
+ "device.*",
51
+ "product_variants.*",
52
+ "product_variants.prices.*",
53
+ "product_variants.product.*",
54
+ ],
55
+ filters: { id: ticketId },
56
+ })
57
+ .catch(() => ({ data: [] }));
58
+ if (!tickets || tickets.length === 0)
59
+ return;
60
+ const ticket = tickets[0];
61
+ // Customer resolution
62
+ let customerName = "Valued Customer";
63
+ let customerEmail = undefined;
64
+ let customerPhone = undefined;
65
+ if (ticket.customer_id) {
66
+ try {
67
+ const customerModule = container.resolve("customer", { allowUnregistered: true });
68
+ if (customerModule) {
69
+ const c = await customerModule.retrieveCustomer(ticket.customer_id);
70
+ if (c) {
71
+ customerName = c.first_name ? `${c.first_name} ${c.last_name || ""}`.trim() : c.email;
72
+ customerEmail = c.email || undefined;
73
+ customerPhone = c.phone || undefined;
74
+ }
75
+ }
76
+ }
77
+ catch (e) { }
78
+ }
79
+ const storeUrl = settings.storefront_url || process.env.STORE_URL || "http://localhost:3000";
80
+ const paymentInfo = (0, payment_link_1.generateRepairPaymentLink)(ticket, storeUrl);
81
+ // Fix 4: Build line items mapping inventory parts from product_variants as well as custom_parts
82
+ const lineItems = [];
83
+ // 1. Map inventory parts from product_variants (SKU, title, unit price, quantity)
84
+ if (ticket.product_variants && ticket.product_variants.length > 0) {
85
+ for (const pv of ticket.product_variants) {
86
+ const qty = Number(pv.quantity || pv.pivot?.quantity || 1);
87
+ const unitPrice = Number(pv.unit_price ?? pv.price ?? pv.prices?.[0]?.amount ?? 0);
88
+ const partTitle = pv.product?.title
89
+ ? `${pv.product.title}${pv.title && pv.title !== "Default Variant" ? ` (${pv.title})` : ""}`
90
+ : pv.title || pv.product?.title || "Inventory Part";
91
+ lineItems.push({
92
+ title: partTitle,
93
+ description: pv.sku ? `SKU: ${pv.sku}` : (pv.product?.title ? `${pv.title || ""}`.trim() : ""),
94
+ quantity: qty,
95
+ unit_price: unitPrice,
96
+ total: qty * unitPrice,
97
+ });
98
+ }
99
+ }
100
+ // 2. Map parts from device.parts_used if present
101
+ if (ticket.device?.parts_used && ticket.device.parts_used.length > 0) {
102
+ for (const part of ticket.device.parts_used) {
103
+ const qty = Number(part.quantity || 1);
104
+ const unitPrice = Number(part.price || part.unit_price || 0);
105
+ lineItems.push({
106
+ title: part.name || part.title || "Replacement Part",
107
+ description: part.sku ? `SKU: ${part.sku}` : "",
108
+ quantity: qty,
109
+ unit_price: unitPrice,
110
+ total: qty * unitPrice,
111
+ });
112
+ }
113
+ }
114
+ // 3. Labor estimate
115
+ if (Number(ticket.labor_estimate || 0) > 0) {
116
+ lineItems.push({
117
+ title: "Labor Charge",
118
+ quantity: 1,
119
+ unit_price: Number(ticket.labor_estimate),
120
+ total: Number(ticket.labor_estimate),
121
+ });
122
+ }
123
+ // 4. Custom parts / services
124
+ if (ticket.custom_parts && ticket.custom_parts.length > 0) {
125
+ for (const cp of ticket.custom_parts) {
126
+ const qty = Number(cp.quantity || 1);
127
+ const unitPrice = Number(cp.price || cp.unit_price || 0);
128
+ lineItems.push({
129
+ title: cp.name || cp.title || "Custom Service / Part",
130
+ description: cp.description || (cp.sku ? `SKU: ${cp.sku}` : ""),
131
+ quantity: qty,
132
+ unit_price: unitPrice,
133
+ total: qty * unitPrice,
134
+ });
135
+ }
136
+ }
137
+ // 5. Fallback line item if none specified
138
+ if (lineItems.length === 0) {
139
+ const tot = Number(ticket.total_actual || ticket.total_estimate || 0);
140
+ lineItems.push({
141
+ title: `Repair Service (#${ticket.ticket_number})`,
142
+ quantity: 1,
143
+ unit_price: tot,
144
+ total: tot,
145
+ });
146
+ }
147
+ const isPaid = ticket.payment_status === "captured" ||
148
+ ticket.payment_status === "paid" ||
149
+ eventName === "repair.payment_received";
150
+ const isAwaitingApproval = ticket.status === "awaiting_approval";
151
+ let docType = isPaid ? "receipt" : (isAwaitingApproval ? "estimate" : "invoice");
152
+ let docTitle = isPaid
153
+ ? "Repair Payment Receipt"
154
+ : isAwaitingApproval
155
+ ? "Repair Estimate / Quote"
156
+ : isCompleted
157
+ ? "Final Repair Invoice"
158
+ : "Repair Invoice";
159
+ if (eventName === "repair.created") {
160
+ docType = "job_card";
161
+ docTitle = "Repair Job Card";
162
+ }
163
+ const displayId = docType === "job_card" ? `JOB-${ticket.ticket_number}` : `RT-${ticket.ticket_number}`;
164
+ const totalEstimate = Number(ticket.total_actual && ticket.total_actual > 0 ? ticket.total_actual : ticket.total_estimate || 0);
165
+ const trackingUrl = ticket.approval_token ? `${storeUrl}/repairs/track?token=${ticket.approval_token}` : undefined;
166
+ const paymentOrTrackingLink = docType === "job_card" ? (trackingUrl || paymentInfo.paymentLink) : paymentInfo.paymentLink;
167
+ // Fix 1: Stop duplicate notifications on repair status changes.
168
+ // The repair subscriber already notifies the customer on repair status changes.
169
+ // Auto-send is kept false for status updates and job cards; receipts and customer reminders auto-send.
170
+ const autoSend = eventName === "repair.payment_received" || eventName === "repair.customer_reminder";
171
+ await documentService.generateDocument({
172
+ display_id: displayId,
173
+ title: docTitle,
174
+ type: docType,
175
+ repair_ticket_id: ticket.id,
176
+ customer: {
177
+ name: customerName,
178
+ email: customerEmail,
179
+ phone: customerPhone,
180
+ },
181
+ items: lineItems,
182
+ total: totalEstimate,
183
+ currency_code: "usd",
184
+ payment_status: isPaid ? "paid" : "unpaid",
185
+ payment_link: paymentOrTrackingLink || undefined,
186
+ auto_send: autoSend,
187
+ email_subject: `${docTitle} for Ticket #${ticket.ticket_number} (${ticket.device?.model_name || "Device"})`,
188
+ notes: ticket.terms_accepted != null
189
+ ? `Intake Consent: Terms Accepted: ${ticket.terms_accepted ? "Yes" : "No"} | Data Wipe: ${ticket.data_wiped_consent ? "Yes" : "No"}`
190
+ : undefined,
191
+ custom_fields: {
192
+ "Device Model": ticket.device?.model_name || "N/A",
193
+ Brand: ticket.device?.brand || "N/A",
194
+ "Serial / IMEI": ticket.device?.serial_number || ticket.device?.imei || "N/A",
195
+ Condition: ticket.device?.condition || "Not specified",
196
+ Accessories: ticket.accessories || "None",
197
+ Technician: ticket.technician_name || "Unassigned",
198
+ Issue: ticket.issue_description || "Standard Repair",
199
+ },
200
+ }, container);
201
+ }
202
+ catch (error) {
203
+ logger.error(`[Documents-Subscriber] Failed processing repair event '${eventName}': ${error.message}`);
204
+ }
205
+ }
206
+ exports.config = {
207
+ event: [
208
+ "repair.status_changed",
209
+ "repair.ticket.compliance_requested",
210
+ "repair.customer_reminder",
211
+ "repair.created",
212
+ "repair.completed",
213
+ "repair.payment_received",
214
+ ],
215
+ };
216
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwYWlyLWRvY3VtZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9yZXBhaXItZG9jdW1lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU1BLDRDQThOQztBQW5PRCxxREFBc0U7QUFDdEUsb0RBQXdEO0FBRXhELHdEQUFrRTtBQUVuRCxLQUFLLFVBQVUseUJBQXlCLENBQUMsRUFDdEQsS0FBSyxFQUNMLFNBQVMsR0FDVztJQUNwQixNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUM7SUFDN0IsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztJQUV4QixNQUFNLENBQUMsSUFBSSxDQUFDLGlEQUFpRCxTQUFTLEdBQUcsQ0FBQyxDQUFDO0lBRTNFLElBQUksQ0FBQztRQUNILE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUFDLDRCQUFnQixFQUFFO1lBQ2pGLGlCQUFpQixFQUFFLElBQUk7U0FDeEIsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGVBQWU7WUFBRSxPQUFPO1FBRTdCLE1BQU0sUUFBUSxHQUFHLE1BQU0sZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRXJELHlGQUF5RjtRQUN6RixNQUFNLFdBQVcsR0FDZixTQUFTLEtBQUssa0JBQWtCO1lBQ2hDLENBQUMsU0FBUyxLQUFLLHVCQUF1QjtnQkFDcEMsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLFdBQVcsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFFakUsdUJBQXVCO1FBQ3ZCLElBQUksV0FBVyxFQUFFLENBQUM7WUFDaEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyw4QkFBOEIsRUFBRSxDQUFDO2dCQUM3QyxNQUFNLENBQUMsSUFBSSxDQUFD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
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.delegateDocumentGeneration = delegateDocumentGeneration;
4
+ /**
5
+ * Universal helper for third-party plugins (e.g. medusajs-repairshop-plugin, custom checkout)
6
+ * to delegate document generation to the Documents Plugin when installed.
7
+ *
8
+ * Usage in another plugin:
9
+ * ```ts
10
+ * import { delegateDocumentGeneration } from "medusajs-documents-plugin";
11
+ *
12
+ * const result = await delegateDocumentGeneration(container, {
13
+ * display_id: "RT-1001",
14
+ * title: "Repair Invoice",
15
+ * type: "invoice",
16
+ * customer: { name: "John Doe", email: "john@example.com" },
17
+ * items: [{ title: "Screen Repair", quantity: 1, unit_price: 120 }],
18
+ * total: 120,
19
+ * currency_code: "usd",
20
+ * auto_send: true
21
+ * });
22
+ * ```
23
+ */
24
+ async function delegateDocumentGeneration(container, input) {
25
+ try {
26
+ const documentService = container.resolve("documents", { allowUnregistered: true });
27
+ if (documentService) {
28
+ return await documentService.generateDocument(input, container);
29
+ }
30
+ }
31
+ catch (err) {
32
+ console.warn("[Documents-Integration] Failed to resolve documents module:", err);
33
+ }
34
+ return null;
35
+ }
36
+ exports.default = delegateDocumentGeneration;
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZWdyYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2ludGVncmF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXVCQSxnRUFhQztBQWpDRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNJLEtBQUssVUFBVSwwQkFBMEIsQ0FDOUMsU0FBMEIsRUFDMUIsS0FBNEI7SUFFNUIsSUFBSSxDQUFDO1FBQ0gsTUFBTSxlQUFlLEdBQVEsU0FBUyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsRUFBRSxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3pGLElBQUksZUFBZSxFQUFFLENBQUM7WUFDcEIsT0FBTyxNQUFNLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDbEUsQ0FBQztJQUNILENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsT0FBTyxDQUFDLElBQUksQ0FBQyw2REFBNkQsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNuRixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQsa0JBQWUsMEJBQTBCLENBQUMifQ==
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateOrderPaymentLink = generateOrderPaymentLink;
7
+ exports.generateRepairPaymentLink = generateRepairPaymentLink;
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ function generateOrderPaymentLink(order, storefrontUrl) {
10
+ let capturedAmount = 0;
11
+ if (order.payment_collections) {
12
+ for (const pc of order.payment_collections) {
13
+ if (pc.captured_amount != null) {
14
+ capturedAmount += Number(pc.captured_amount);
15
+ }
16
+ else if (pc.payments) {
17
+ capturedAmount += pc.payments.reduce((acc, p) => {
18
+ const isPaid = Boolean(p.captured_at) && !p.canceled_at;
19
+ return acc + (isPaid ? Number(p.amount) : 0);
20
+ }, 0);
21
+ }
22
+ }
23
+ }
24
+ const total = Number(order.total || 0);
25
+ const remainingBalance = Math.max(0, total - capturedAmount);
26
+ if (remainingBalance <= 0) {
27
+ return {
28
+ paymentLink: null,
29
+ remainingBalance: 0,
30
+ isUnpaid: false,
31
+ };
32
+ }
33
+ // Generate secure Paystack HMAC storefront payment URL
34
+ const secretKey = process.env.MEDUSA_PUBLISHABLE_KEY ||
35
+ process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ||
36
+ process.env.MEDUSA_PUBLISHABLE_API_KEY ||
37
+ "super_secret_fallback_key";
38
+ const hash = crypto_1.default
39
+ .createHmac("sha256", secretKey)
40
+ .update(order.id)
41
+ .digest("hex");
42
+ const cleanStorefrontUrl = storefrontUrl.replace(/\/$/, "");
43
+ const paymentLink = `${cleanStorefrontUrl}/pay/${hash}/${order.id}`;
44
+ return {
45
+ paymentLink,
46
+ remainingBalance,
47
+ isUnpaid: true,
48
+ };
49
+ }
50
+ function generateRepairPaymentLink(ticket, storefrontUrl) {
51
+ const targetTotal = Number((ticket.total_actual && ticket.total_actual > 0) ? ticket.total_actual : ticket.total_estimate || 0);
52
+ const paid = Number(ticket.amount_paid || 0);
53
+ const remainingBalance = Math.max(0, targetTotal - paid);
54
+ if (remainingBalance <= 0 || !ticket.approval_token) {
55
+ return {
56
+ paymentLink: null,
57
+ remainingBalance,
58
+ isUnpaid: false,
59
+ };
60
+ }
61
+ const cleanStorefrontUrl = storefrontUrl.replace(/\/$/, "");
62
+ const paymentLink = `${cleanStorefrontUrl}/repairs/track?token=${ticket.approval_token}`;
63
+ return {
64
+ paymentLink,
65
+ remainingBalance,
66
+ isUnpaid: true,
67
+ };
68
+ }
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5bWVudC1saW5rLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3BheW1lbnQtbGluay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVFBLDREQStDQztBQUVELDhEQXFCQztBQTlFRCxvREFBNEI7QUFRNUIsU0FBZ0Isd0JBQXdCLENBQUMsS0FBVSxFQUFFLGFBQXFCO0lBQ3hFLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBQztJQUV2QixJQUFJLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzlCLEtBQUssTUFBTSxFQUFFLElBQUksS0FBSyxDQUFDLG1CQUE0QixFQUFFLENBQUM7WUFDcEQsSUFBSSxFQUFFLENBQUMsZUFBZSxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUMvQixjQUFjLElBQUksTUFBTSxDQUFDLEVBQUUsQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUMvQyxDQUFDO2lCQUFNLElBQUksRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUN2QixjQUFjLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFXLEVBQUUsQ0FBTSxFQUFFLEVBQUU7b0JBQzNELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDO29CQUN4RCxPQUFPLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQy9DLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNSLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxHQUFHLGNBQWMsQ0FBQyxDQUFDO0lBRTdELElBQUksZ0JBQWdCLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTztZQUNMLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLGdCQUFnQixFQUFFLENBQUM7WUFDbkIsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQztJQUNKLENBQUM7SUFFRCx1REFBdUQ7SUFDdkQsTUFBTSxTQUFTLEdBQ2IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0I7UUFDbEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0M7UUFDOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEI7UUFDdEMsMkJBQTJCLENBQUM7SUFFOUIsTUFBTSxJQUFJLEdBQUcsZ0JBQU07U0FDaEIsVUFBVSxDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUM7U0FDL0IsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7U0FDaEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRWpCLE1BQU0sa0JBQWtCLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUQsTUFBTSxXQUFXLEdBQUcsR0FBRyxrQkFBa0IsUUFBUSxJQUFJLElBQUksS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBRXBFLE9BQU87UUFDTCxXQUFXO1FBQ1gsZ0JBQWdCO1FBQ2hCLFFBQVEsRUFBRSxJQUFJO0tBQ2YsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQix5QkFBeUIsQ0FBQyxNQUFXLEVBQUUsYUFBcUI7SUFDMUUsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVksSUFBSSxNQUFNLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2hJLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzdDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBRXpELElBQUksZ0JBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ3BELE9BQU87WUFDTCxXQUFXLEVBQUUsSUFBSTtZQUNqQixnQkFBZ0I7WUFDaEIsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLGtCQUFrQixHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzVELE1BQU0sV0FBVyxHQUFHLEdBQUcsa0JBQWtCLHdCQUF3QixNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7SUFFekYsT0FBTztRQUNMLFdBQVc7UUFDWCxnQkFBZ0I7UUFDaEIsUUFBUSxFQUFFLElBQUk7S0FDZixDQUFDO0FBQ0osQ0FBQyJ9
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createManualDocumentWorkflow = exports.createManualDocumentStep = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const documents_1 = require("../modules/documents");
6
+ exports.createManualDocumentStep = (0, workflows_sdk_1.createStep)("create-manual-document-step", async (input, { container }) => {
7
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE);
8
+ const result = await documentService.generateDocument({
9
+ ...input,
10
+ auto_send: input.send_email_now || input.auto_send,
11
+ }, container);
12
+ return new workflows_sdk_1.StepResponse(result, { id: result.record.id });
13
+ }, async (compensationData, { container }) => {
14
+ if (compensationData?.id) {
15
+ try {
16
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE);
17
+ await documentService.deleteDocumentRecords(compensationData.id);
18
+ }
19
+ catch (e) { }
20
+ }
21
+ });
22
+ exports.createManualDocumentWorkflow = (0, workflows_sdk_1.createWorkflow)("create-manual-document-workflow", (input) => {
23
+ const result = (0, exports.createManualDocumentStep)(input);
24
+ return new workflows_sdk_1.WorkflowResponse(result);
25
+ });
26
+ exports.default = exports.createManualDocumentWorkflow;
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLW1hbnVhbC1kb2N1bWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3MvY3JlYXRlLW1hbnVhbC1kb2N1bWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxRUFLMkM7QUFDM0Msb0RBQXdEO0FBTzNDLFFBQUEsd0JBQXdCLEdBQUcsSUFBQSwwQkFBVSxFQUNoRCw2QkFBNkIsRUFDN0IsS0FBSyxFQUFFLEtBQWdDLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQ3hELE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUFDLDRCQUFnQixDQUFDLENBQUM7SUFDbkYsTUFBTSxNQUFNLEdBQUcsTUFBTSxlQUFlLENBQUMsZ0JBQWdCLENBQUM7UUFDcEQsR0FBRyxLQUFLO1FBQ1IsU0FBUyxFQUFFLEtBQUssQ0FBQyxjQUFjLElBQUksS0FBSyxDQUFDLFNBQVM7S0FDbkQsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUVkLE9BQU8sSUFBSSw0QkFBWSxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDNUQsQ0FBQyxFQUNELEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDeEMsSUFBSSxnQkFBZ0IsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUN6QixJQUFJLENBQUM7WUFDSCxNQUFNLGVBQWUsR0FBMEIsU0FBUyxDQUFDLE9BQU8sQ0FBQyw0QkFBZ0IsQ0FBQyxDQUFDO1lBQ25GLE1BQU0sZUFBZSxDQUFDLHFCQUFxQixDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUEsQ0FBQztJQUNoQixDQUFDO0FBQ0gsQ0FBQyxDQUNGLENBQUM7QUFFVyxRQUFBLDRCQUE0QixHQUFHLElBQUEsOEJBQWMsRUFDeEQsaUNBQWlDLEVBQ2pDLENBQUMsS0FBZ0MsRUFBRSxFQUFFO0lBQ25DLE1BQU0sTUFBTSxHQUFHLElBQUEsZ0NBQXdCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDL0MsT0FBTyxJQUFJLGdDQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3RDLENBQUMsQ0FDRixDQUFDO0FBRUYsa0JBQWUsb0NBQTRCLENBQUMifQ==
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDocumentWorkflow = exports.generateDocumentStep = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const documents_1 = require("../modules/documents");
6
+ exports.generateDocumentStep = (0, workflows_sdk_1.createStep)("generate-document-step", async (input, { container }) => {
7
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE);
8
+ const result = await documentService.generateDocument(input, container);
9
+ return new workflows_sdk_1.StepResponse(result, { id: result.record.id });
10
+ }, async (compensationData, { container }) => {
11
+ if (compensationData?.id) {
12
+ try {
13
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE);
14
+ await documentService.deleteDocumentRecords(compensationData.id);
15
+ }
16
+ catch (e) { }
17
+ }
18
+ });
19
+ exports.generateDocumentWorkflow = (0, workflows_sdk_1.createWorkflow)("generate-document-workflow", (input) => {
20
+ const result = (0, exports.generateDocumentStep)(input);
21
+ return new workflows_sdk_1.WorkflowResponse(result);
22
+ });
23
+ exports.default = exports.generateDocumentWorkflow;
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGUtZG9jdW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2dlbmVyYXRlLWRvY3VtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUsyQztBQUMzQyxvREFBd0Q7QUFHM0MsUUFBQSxvQkFBb0IsR0FBRyxJQUFBLDBCQUFVLEVBQzVDLHdCQUF3QixFQUN4QixLQUFLLEVBQUUsS0FBNEIsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDcEQsTUFBTSxlQUFlLEdBQTBCLFNBQVMsQ0FBQyxPQUFPLENBQUMsNEJBQWdCLENBQUMsQ0FBQztJQUNuRixNQUFNLE1BQU0sR0FBRyxNQUFNLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDeEUsT0FBTyxJQUFJLDRCQUFZLENBQUMsTUFBTSxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUM1RCxDQUFDLEVBQ0QsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRTtJQUN4QyxJQUFJLGdCQUFnQixFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQztZQUNILE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUFDLDRCQUFnQixDQUFDLENBQUM7WUFDbkYsTUFBTSxlQUFlLENBQUMscUJBQXFCLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQSxDQUFDO0lBQ2hCLENBQUM7QUFDSCxDQUFDLENBQ0YsQ0FBQztBQUVXLFFBQUEsd0JBQXdCLEdBQUcsSUFBQSw4QkFBYyxFQUNwRCw0QkFBNEIsRUFDNUIsQ0FBQyxLQUE0QixFQUFFLEVBQUU7SUFDL0IsTUFBTSxNQUFNLEdBQUcsSUFBQSw0QkFBb0IsRUFBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxPQUFPLElBQUksZ0NBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDdEMsQ0FBQyxDQUNGLENBQUM7QUFFRixrQkFBZSxnQ0FBd0IsQ0FBQyJ9
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./generate-document"), exports);
18
+ __exportStar(require("./send-document-notification"), exports);
19
+ __exportStar(require("./create-manual-document"), exports);
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxzREFBb0M7QUFDcEMsK0RBQTZDO0FBQzdDLDJEQUF5QyJ9
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendDocumentNotificationWorkflow = exports.sendDocumentNotificationStep = void 0;
4
+ const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
5
+ const documents_1 = require("../modules/documents");
6
+ const notification_sender_1 = require("../services/notification-sender");
7
+ exports.sendDocumentNotificationStep = (0, workflows_sdk_1.createStep)("send-document-notification-step", async (input, { container }) => {
8
+ const documentService = container.resolve(documents_1.DOCUMENTS_MODULE);
9
+ const record = await documentService.retrieveDocumentRecord(input.documentId);
10
+ const settings = await documentService.getSettings();
11
+ const dispatchResult = await notification_sender_1.NotificationSender.send({
12
+ container,
13
+ document: {
14
+ id: record.id,
15
+ display_id: record.display_id,
16
+ title: record.title,
17
+ type: record.type,
18
+ customer_name: record.customer_name,
19
+ customer_email: record.customer_email,
20
+ customer_phone: record.customer_phone,
21
+ total_amount: record.total_amount,
22
+ currency_code: record.currency_code,
23
+ payment_status: record.payment_status,
24
+ payment_link: record.payment_link,
25
+ short_payment_link: record.short_payment_link,
26
+ pdf_url: record.pdf_url,
27
+ short_pdf_link: record.short_pdf_link,
28
+ custom_message: input.custom_message,
29
+ subject: input.subject,
30
+ },
31
+ channels: input.channels,
32
+ settings,
33
+ });
34
+ return new workflows_sdk_1.StepResponse(dispatchResult);
35
+ });
36
+ exports.sendDocumentNotificationWorkflow = (0, workflows_sdk_1.createWorkflow)("send-document-notification-workflow", (input) => {
37
+ const result = (0, exports.sendDocumentNotificationStep)(input);
38
+ return new workflows_sdk_1.WorkflowResponse(result);
39
+ });
40
+ exports.default = exports.sendDocumentNotificationWorkflow;
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC1kb2N1bWVudC1ub3RpZmljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL3NlbmQtZG9jdW1lbnQtbm90aWZpY2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFFQUsyQztBQUMzQyxvREFBd0Q7QUFFeEQseUVBQXFFO0FBU3hELFFBQUEsNEJBQTRCLEdBQUcsSUFBQSwwQkFBVSxFQUNwRCxpQ0FBaUMsRUFDakMsS0FBSyxFQUFFLEtBQW9DLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQzVELE1BQU0sZUFBZSxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUFDLDRCQUFnQixDQUFDLENBQUM7SUFDbkYsTUFBTSxNQUFNLEdBQUcsTUFBTSxlQUFlLENBQUMsc0JBQXNCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzlFLE1BQU0sUUFBUSxHQUFHLE1BQU0sZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBRXJELE1BQU0sY0FBYyxHQUFHLE1BQU0sd0NBQWtCLENBQUMsSUFBSSxDQUFDO1FBQ25ELFNBQVM7UUFDVCxRQUFRLEVBQUU7WUFDUixFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUU7WUFDYixVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7WUFDN0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLO1lBQ25CLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtZQUNqQixhQUFhLEVBQUUsTUFBTSxDQUFDLGFBQWE7WUFDbkMsY0FBYyxFQUFFLE1BQU0sQ0FBQyxjQUFjO1lBQ3JDLGNBQWMsRUFBRSxNQUFNLENBQUMsY0FBYztZQUNyQyxZQUFZLEVBQUUsTUFBTSxDQUFDLFlBQVk7WUFDakMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxhQUFhO1lBQ25DLGNBQWMsRUFBRSxNQUFNLENBQUMsY0FBYztZQUNyQyxZQUFZLEVBQUUsTUFBTSxDQUFDLFlBQVk7WUFDakMsa0JBQWtCLEVBQUUsTUFBTSxDQUFDLGtCQUFrQjtZQUM3QyxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87WUFDdkIsY0FBYyxFQUFFLE1BQU0sQ0FBQyxjQUFjO1lBQ3JDLGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYztZQUNwQyxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87U0FDdkI7UUFDRCxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7UUFDeEIsUUFBUTtLQUNULENBQUMsQ0FBQztJQUVILE9BQU8sSUFBSSw0QkFBWSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0FBQzFDLENBQUMsQ0FDRixDQUFDO0FBRVcsUUFBQSxnQ0FBZ0MsR0FBRyxJQUFBLDhCQUFjLEVBQzVELHFDQUFxQyxFQUNyQyxDQUFDLEtBQW9DLEVBQUUsRUFBRTtJQUN2QyxNQUFNLE1BQU0sR0FBRyxJQUFBLG9DQUE0QixFQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25ELE9BQU8sSUFBSSxnQ0FBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0QyxDQUFDLENBQ0YsQ0FBQztBQUVGLGtCQUFlLHdDQUFnQyxDQUFDIn0=
package/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to `medusajs-documents-plugin` will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [1.1.0] - 2026-10-12
11
+
12
+ ### Minor Release: Repair Job Card Intake & Automated Release Pipeline
13
+
14
+ #### ✨ What's New in v1.1.0
15
+
16
+ - **First-Class Repair Job Card Generation (`type: "job_card"`)**:
17
+ - Automatically triggered upon repair intake (`repair.created`).
18
+ - Device specifications: Brand, Model, Serial Number, and IMEI.
19
+ - Workshop physical intake condition, accessories left, and customer reported fault.
20
+ - Workshop technician diagnostic checklist `[ ]`.
21
+ - Dual physical sign-off lines: **Customer Signature** & **Workshop Technician Signature**.
22
+ - Dynamic QR code directing straight to customer online repair tracking portal.
23
+
24
+ - **Repair Event Subscribers & Delegation**:
25
+ - Event listeners for `repair.created` and `repair.payment_received`.
26
+ - Automatic Query Graph hydration of repair ticket details for document rendering.
27
+ - Seamless delegation from `Meduajs-repair-plugin` with fallback protection.
28
+
29
+ - **Automated CI/CD & Distribution Pipeline**:
30
+ - GitHub Actions release pipeline with automated version tagging.
31
+ - Dynamic changelog extraction as release notes.
32
+ - Release asset bundling with compressed `.zip` distribution archive and `.tgz` npm package.
33
+ - Automated public publishing to the npm registry with authentication tokens.
34
+
35
+ ---
36
+
37
+ ## [1.0.0] - 2026-10-12
38
+
39
+ ### Initial Release: Medusa v2 Documents & Accounting Plugin
40
+
41
+ Comprehensive document generation, accounting synchronization, and multi-channel notification engine for Medusa v2 with Zoho Books integration, local PDFKit fallback, dynamic QR codes, short links, and a unified Admin Documents Hub.
42
+
43
+ #### ✨ Key Features
44
+
45
+ - **First-Class Repair Job Cards (`job_card`)**:
46
+ - Automatic intake generation when `repair.created` fires.
47
+ - Device specifications (Brand, Model, Serial Number, IMEI).
48
+ - Cosmetic condition, accessories left with workshop, and reported fault description.
49
+ - Diagnostic checklist `[ ]` tasks for workshop technicians.
50
+ - Dual physical sign-off lines: **Customer Signature** & **Workshop Technician Signature**.
51
+ - Scannable QR code directing straight to customer online repair tracking portal.
52
+
53
+ - **Zoho Books Synchronization**:
54
+ - Automatic customer contact creation and matching.
55
+ - Real-time generation of Invoices, Estimates, and Payment Receipts via Zoho Books API.
56
+ - Native Zoho invoice QR code customization and notes injection.
57
+ - Two-way reference mapping with local fallback records.
58
+
59
+ - **Local PDFKit Generation Engine (Fallback)**:
60
+ - 3 modern, clean, print-ready document templates:
61
+ - **Modern Minimalist**: Crisp clean lines, typography-driven hierarchy, accent color branding.
62
+ - **Classic Corporate**: Traditional business layout with header grids and signature blocks.
63
+ - **Clean Tech Monospace**: Tech-repair inspired monospace layout with scannable barcodes and checklist grids.
64
+ - Document types: Job Cards, Tax Invoices, Payment Receipts, Estimates / Quotes, Packing Slips, and Custom Certificates.
65
+ - Complete removal of semi-transparent watermarks for sharp, professional PDFs.
66
+
67
+ - **Paystack Dynamic Scan-to-Pay QR Codes & Short Links**:
68
+ - Direct QR code embedded onto invoices and estimates for instant mobile checkout.
69
+ - Built-in URL shortener (`/store/documents/r/:code`) for clean, deliverable SMS and WhatsApp links.
70
+
71
+ - **Multi-Channel Notification Dispatcher**:
72
+ - **Email**: Responsive HTML emails with document branding, summary tables, and download/pay CTAs.
73
+ - **SMS**: Concise SMS notifications powered by TalkSasa SMS provider.
74
+ - **WhatsApp**: Rich formatting with emoji bullets and direct short links.
75
+
76
+ - **Unified Admin Documents Hub (`/app/documents`)**:
77
+ - **All Documents Tab**: Search, filter by document type (including Job Cards), view statuses, create manual invoices, and resend notifications.
78
+ - **PDF Templates Tab**: Live document previewers and template style switchers.
79
+ - **Automations Tab**: Per-event subscriber toggle switches for order and repair events.
80
+ - **Settings Tab**: Zoho Books OAuth configuration, domain selector, company branding, and QR options.
81
+
82
+ - **Automated Event Subscribers**:
83
+ - Order events: `order.placed`, `order.completed`, `payment.captured`, `order.fulfillment_created`.
84
+ - Repair events: `repair.created`, `repair.status_changed`, `repair.payment_received`, `repair.completed`, `repair.customer_reminder`.
85
+
86
+ - **Graceful Integration Utility**:
87
+ - Exported `delegateDocumentGeneration` and `DOCUMENTS_MODULE` helpers allowing external plugins (like `Meduajs-repair-plugin`) to delegate document generation while maintaining safe fallbacks.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Urban Device Care
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.