medusa-pos-plugin 0.0.34 → 0.0.35

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.
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = GET;
4
+ exports.POST = POST;
5
+ const utils_1 = require("@medusajs/framework/utils");
6
+ const barcode_labels_1 = require("../../../utils/barcode-labels");
7
+ const VARIANT_FIELDS = [
8
+ "id",
9
+ "barcode",
10
+ "sku",
11
+ "product.id",
12
+ "product.title",
13
+ "options.value",
14
+ "options.option.title",
15
+ "calculated_price.*",
16
+ "price_set.prices.amount",
17
+ "price_set.prices.currency_code",
18
+ "price_set.prices.price_list_id",
19
+ ];
20
+ function isVariantRow(value) {
21
+ return (!!value &&
22
+ typeof value === "object" &&
23
+ typeof value.id === "string");
24
+ }
25
+ async function loadContactDetails(scope) {
26
+ try {
27
+ const dynamicConfigService = scope.resolve("dynamic_config");
28
+ return (0, barcode_labels_1.contactDetailsFromConfig)(await dynamicConfigService.listValues());
29
+ }
30
+ catch (configError) {
31
+ console.warn("[barcode-template] Could not fetch dynamic config:", configError);
32
+ return { phone: "", email: "", address: "" };
33
+ }
34
+ }
35
+ async function resolveRegionId(scope, requested) {
36
+ if (requested)
37
+ return requested;
38
+ try {
39
+ const regionModule = scope.resolve(utils_1.Modules.REGION);
40
+ const regions = await regionModule.listRegions({}, { take: 20 });
41
+ const inr = regions.find((r) => (r.currency_code || "").toLowerCase() === "inr");
42
+ return inr?.id || regions[0]?.id || "";
43
+ }
44
+ catch (regionError) {
45
+ console.warn("[barcode-template] region resolve failed:", regionError);
46
+ return "";
47
+ }
48
+ }
49
+ /**
50
+ * GET /admin/barcode-template
51
+ * Returns raw template + contact details (legacy / preview).
52
+ */
53
+ async function GET(req, res) {
54
+ try {
55
+ const template = (0, barcode_labels_1.loadBarcodeTemplate)();
56
+ const contactDetails = await loadContactDetails(req.scope);
57
+ res.json({ template, contactDetails });
58
+ }
59
+ catch (error) {
60
+ console.error("Error reading barcode template:", error);
61
+ res.status(500).json({ error: "Failed to load barcode template" });
62
+ }
63
+ }
64
+ /**
65
+ * POST /admin/barcode-template
66
+ * Body: { items: [{ variant_id, quantity }], region_id?, print_width?, print_height? }
67
+ * or legacy { variant_ids: string[] }
68
+ * Returns ready-to-print HTML with all variables filled on the backend.
69
+ * Quantity repeats labels (unique SVG ids per copy).
70
+ */
71
+ async function POST(req, res) {
72
+ try {
73
+ const body = (0, barcode_labels_1.parseBarcodePrintBody)(req.body);
74
+ const printQueue = (0, barcode_labels_1.buildPrintQueue)(body);
75
+ if (printQueue.length === 0) {
76
+ res.status(400).json({ error: "items or variant_ids is required" });
77
+ return;
78
+ }
79
+ const uniqueVariantIds = [...new Set(printQueue)];
80
+ const printWidth = Number(body.print_width) || 2;
81
+ const printHeight = Number(body.print_height) || 60;
82
+ const template = (0, barcode_labels_1.loadBarcodeTemplate)();
83
+ const contactHtml = (0, barcode_labels_1.buildContactHtml)(await loadContactDetails(req.scope));
84
+ const regionId = await resolveRegionId(req.scope, body.region_id);
85
+ const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
86
+ const { data: variantsRaw = [] } = await query.graph({
87
+ entity: "product_variant",
88
+ fields: VARIANT_FIELDS,
89
+ filters: { id: uniqueVariantIds },
90
+ ...(regionId
91
+ ? {
92
+ context: {
93
+ calculated_price: (0, utils_1.QueryContext)({
94
+ region_id: regionId,
95
+ currency_code: "inr",
96
+ }),
97
+ },
98
+ }
99
+ : {}),
100
+ });
101
+ const variants = (Array.isArray(variantsRaw) ? variantsRaw : []).filter(isVariantRow);
102
+ const byId = new Map(variants.map((v) => [v.id, v]));
103
+ const ordered = printQueue
104
+ .map((id) => byId.get(id))
105
+ .filter((v) => !!v);
106
+ if (ordered.length === 0) {
107
+ res.status(404).json({ error: "No variants found for the given ids" });
108
+ return;
109
+ }
110
+ const { html, count } = (0, barcode_labels_1.renderBarcodeLabelsHtml)({
111
+ template,
112
+ variants: ordered,
113
+ contactHtml,
114
+ printWidth,
115
+ printHeight,
116
+ });
117
+ res.json({
118
+ html,
119
+ count,
120
+ variants: uniqueVariantIds.length,
121
+ });
122
+ }
123
+ catch (error) {
124
+ console.error("[barcode-template] POST error:", error);
125
+ res.status(500).json({
126
+ error: error instanceof Error && error.message
127
+ ? error.message
128
+ : "Failed to build barcode print HTML",
129
+ });
130
+ }
131
+ }
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2JhcmNvZGUtdGVtcGxhdGUvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUErRkEsa0JBWUM7QUFTRCxvQkF3RUM7QUEzTEQscURBSWtDO0FBQ2xDLGtFQVNzQztBQXVCdEMsTUFBTSxjQUFjLEdBQUc7SUFDckIsSUFBSTtJQUNKLFNBQVM7SUFDVCxLQUFLO0lBQ0wsWUFBWTtJQUNaLGVBQWU7SUFDZixlQUFlO0lBQ2Ysc0JBQXNCO0lBQ3RCLG9CQUFvQjtJQUNwQix5QkFBeUI7SUFDekIsZ0NBQWdDO0lBQ2hDLGdDQUFnQztDQUNqQyxDQUFBO0FBRUQsU0FBUyxZQUFZLENBQUMsS0FBYztJQUNsQyxPQUFPLENBQ0wsQ0FBQyxDQUFDLEtBQUs7UUFDUCxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQ3pCLE9BQVEsS0FBMEIsQ0FBQyxFQUFFLEtBQUssUUFBUSxDQUNuRCxDQUFBO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxrQkFBa0IsQ0FDL0IsS0FBNkI7SUFFN0IsSUFBSSxDQUFDO1FBQ0gsTUFBTSxvQkFBb0IsR0FDeEIsS0FBSyxDQUFDLE9BQU8sQ0FBdUIsZ0JBQWdCLENBQUMsQ0FBQTtRQUN2RCxPQUFPLElBQUEseUNBQXdCLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFBO0lBQzFFLENBQUM7SUFBQyxPQUFPLFdBQVcsRUFBRSxDQUFDO1FBQ3JCLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0RBQW9ELEVBQUUsV0FBVyxDQUFDLENBQUE7UUFDL0UsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLENBQUE7SUFDOUMsQ0FBQztBQUNILENBQUM7QUFFRCxLQUFLLFVBQVUsZUFBZSxDQUM1QixLQUE2QixFQUM3QixTQUFr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
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.POST = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const barcode_ean13_1 = require("../../../../utils/barcode-ean13");
6
+ function readVariantIds(body) {
7
+ if (!body || typeof body !== "object")
8
+ return [];
9
+ const ids = body.variantIds;
10
+ if (!Array.isArray(ids))
11
+ return [];
12
+ return ids.filter((id) => typeof id === "string" && !!id);
13
+ }
14
+ /**
15
+ * POST /admin/barcodes/bulk-generate
16
+ * Body: { variantIds: string[] }
17
+ * Writes a deterministic SHA-256 EAN-13 barcode onto each variant.
18
+ */
19
+ const POST = async (req, res) => {
20
+ try {
21
+ const productModuleService = req.scope.resolve(utils_1.Modules.PRODUCT);
22
+ const variantIds = readVariantIds(req.body);
23
+ if (variantIds.length === 0) {
24
+ res.json({ success: true, message: "No variants requested.", count: 0 });
25
+ return;
26
+ }
27
+ // Fetch variant details with parent product & options relations
28
+ const variants = await productModuleService.listProductVariants({ id: variantIds }, { relations: ["product", "options", "options.option"] });
29
+ const updates = [];
30
+ for (const id of variantIds) {
31
+ const variant = variants.find((v) => v.id === id);
32
+ const barcode = (0, barcode_ean13_1.generateDeterministicBarcodeSHA256)(variant?.product?.title || "", variant?.title || "", variant?.options || [], variant?.weight, variant?.width, variant?.length, variant?.height);
33
+ updates.push({ id, barcode });
34
+ }
35
+ for (const update of updates) {
36
+ await productModuleService.updateProductVariants(update.id, {
37
+ barcode: update.barcode,
38
+ });
39
+ }
40
+ res.json({
41
+ success: true,
42
+ message: `Successfully generated SHA-256 deterministic barcodes for ${updates.length} variants.`,
43
+ count: updates.length,
44
+ });
45
+ }
46
+ catch (error) {
47
+ console.error("Bulk barcode generation error:", error);
48
+ res.status(500).json({
49
+ success: false,
50
+ message: error instanceof Error && error.message
51
+ ? error.message
52
+ : "Internal server error",
53
+ });
54
+ }
55
+ };
56
+ exports.POST = POST;
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2JhcmNvZGVzL2J1bGstZ2VuZXJhdGUvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEscURBQW1EO0FBQ25ELG1FQUd3QztBQWF4QyxTQUFTLGNBQWMsQ0FBQyxJQUFhO0lBQ25DLElBQUksQ0FBQyxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sRUFBRSxDQUFBO0lBQ2hELE1BQU0sR0FBRyxHQUFJLElBQWlDLENBQUMsVUFBVSxDQUFBO0lBQ3pELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztRQUFFLE9BQU8sRUFBRSxDQUFBO0lBQ2xDLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBZ0IsRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLFFBQVEsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUE7QUFDekUsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQ3ZCLEdBQWtCLEVBQ2xCLEdBQW1CLEVBQ0osRUFBRTtJQUNqQixJQUFJLENBQUM7UUFDSCxNQUFNLG9CQUFvQixHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUM1QyxlQUFPLENBQUMsT0FBTyxDQUNoQixDQUFBO1FBRUQsTUFBTSxVQUFVLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUMzQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDNUIsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQ3hFLE9BQU07UUFDUixDQUFDO1FBRUQsZ0VBQWdFO1FBQ2hFLE1BQU0sUUFBUSxHQUNaLE1BQU0sb0JBQW9CLENBQUMsbUJBQW1CLENBQzVDLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxFQUNsQixFQUFFLFNBQVMsRUFBRSxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLENBQUMsRUFBRSxDQUN4RCxDQUFBO1FBRUgsTUFBTSxPQUFPLEdBQTJDLEVBQUUsQ0FBQTtRQUUxRCxLQUFLLE1BQU0sRUFBRSxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQzVCLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7WUFDakQsTUFBTSxPQUFPLEdBQUcsSUFBQSxrREFBa0MsRUFDaEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLElBQUksRUFBRSxFQUM3QixPQUFPLEVBQUUsS0FBSyxJQUFJLEVBQUUsRUFDcEIsT0FBTyxFQUFFLE9BQU8sSUFBSSxFQUFFLEVBQ3RCLE9BQU8sRUFBRSxNQUFNLEVBQ2YsT0FBTyxFQUFFLEtBQUssRUFDZCxPQUFPLEVBQUUsTUFBTSxFQUNmLE9BQU8sRUFBRSxNQUFNLENBQ2hCLENBQUE7WUFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUE7UUFDL0IsQ0FBQztRQUVELEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxFQUFFLENBQUM7WUFDN0IsTUFBTSxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFO2dCQUMxRCxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87YUFDeEIsQ0FBQyxDQUFBO1FBQ0osQ0FBQztRQUVELEdBQUcsQ0FBQyxJQUFJLENBQUM7WUFDUCxPQUFPLEVBQUUsSUFBSTtZQUNiLE9BQU8sRUFBRSw2REFBNkQsT0FBTyxDQUFDLE1BQU0sWUFBWTtZQUNoRyxLQUFLLEVBQUUsT0FBTyxDQUFDLE1BQU07U0FDdEIsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixPQUFPLENBQUMsS0FBSyxDQUFDLGdDQUFnQyxFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQ3RELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ25CLE9BQU8sRUFBRSxLQUFLO1lBQ2QsT0FBTyxFQUNMLEtBQUssWUFBWSxLQUFLLElBQUksS0FBSyxDQUFDLE9BQU87Z0JBQ3JDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTztnQkFDZixDQUFDLENBQUMsdUJBQXVCO1NBQzlCLENBQUMsQ0FBQTtJQUNKLENBQUM7QUFDSCxDQUFDLENBQUE7QUEzRFksUUFBQSxJQUFJLFFBMkRoQiJ9
@@ -3,38 +3,48 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GET = GET;
4
4
  const utils_1 = require("@medusajs/framework/utils");
5
5
  const POSMAN_PREFIX = "POSMAN-";
6
+ function isPosManualPromotion(p) {
7
+ const code = String(p.code || "");
8
+ return code.startsWith(POSMAN_PREFIX) || p.metadata?.source === "pos_manual";
9
+ }
6
10
  /**
7
11
  * GET /admin/pos/manual-discounts
8
- * Lists POS manual-discount promotions (POSMAN-*) for POS + external UI.
9
- * Includes inactive codes (hidden from Admin active promotions).
12
+ * Lists POS manual-discount promotions (POSMAN-*) and Admin-created promo codes
13
+ * for the POS Discounts page. Includes inactive codes.
10
14
  */
11
15
  async function GET(req, res) {
12
16
  const query = (req.query || {});
13
- const limit = Math.min(Math.max(Number(query.limit) || 50, 1), 100);
17
+ const limit = Math.min(Math.max(Number(query.limit) || 50, 1), 200);
14
18
  const offset = Math.max(Number(query.offset) || 0, 0);
15
19
  const q = (query.q || "").trim().toLowerCase();
16
20
  try {
17
21
  const promotionModule = req.scope.resolve(utils_1.Modules.PROMOTION);
18
- // Fetch a window of promotions; filter POSMAN in-process (prefix match).
19
- const take = Math.min(offset + limit + 200, 500);
20
- const [rows] = await promotionModule.listAndCountPromotions({}, {
21
- take,
22
- skip: 0,
22
+ const config = {
23
23
  order: { created_at: "DESC" },
24
24
  relations: ["application_method"],
25
- });
26
- let manual = (rows || []).filter((p) => {
27
- const code = String(p.code || "");
28
- const source = p.metadata?.source;
29
- return code.startsWith(POSMAN_PREFIX) || source === "pos_manual";
25
+ };
26
+ // POSMAN codes are created per sale, so Admin promos are queried separately
27
+ // to keep them from being pushed out of the POSMAN window.
28
+ const take = Math.min(offset + limit + 200, 500);
29
+ const [manualRows, adminRows] = await Promise.all([
30
+ promotionModule.listPromotions({}, { ...config, take, skip: 0 }),
31
+ promotionModule.listPromotions({ code: { $not: { $like: `${POSMAN_PREFIX}%` } } }, { ...config, take: 500, skip: 0 }),
32
+ ]);
33
+ const manual = (manualRows || []).filter(isPosManualPromotion);
34
+ const admin = (adminRows || []).filter((p) => !isPosManualPromotion(p));
35
+ let combined = [...manual, ...admin].sort((a, b) => {
36
+ const at = new Date(a.created_at ?? 0).getTime();
37
+ const bt = new Date(b.created_at ?? 0).getTime();
38
+ return bt - at;
30
39
  });
31
40
  if (q) {
32
- manual = manual.filter((p) => {
41
+ combined = combined.filter((p) => {
33
42
  const hay = [
34
43
  p.code,
35
44
  p.metadata?.draft_order_id,
36
45
  p.metadata?.applied_by,
37
46
  String(p.metadata?.amount ?? ""),
47
+ String(p.application_method?.value ?? ""),
38
48
  ]
39
49
  .filter(Boolean)
40
50
  .join(" ")
@@ -42,23 +52,32 @@ async function GET(req, res) {
42
52
  return hay.includes(q);
43
53
  });
44
54
  }
45
- const count = manual.length;
46
- const page = manual.slice(offset, offset + limit).map((p) => ({
47
- id: p.id,
48
- code: p.code,
49
- status: p.status,
50
- amount: p.metadata?.amount ??
51
- p.application_method?.value ??
52
- null,
53
- currency_code: p.metadata?.currency_code ??
54
- p.application_method?.currency_code ??
55
- null,
56
- draft_order_id: p.metadata?.draft_order_id ?? null,
57
- applied_by: p.metadata?.applied_by ?? null,
58
- applied_at: p.metadata?.applied_at ?? p.created_at ?? null,
59
- created_at: p.created_at ?? null,
60
- metadata: p.metadata ?? null,
61
- }));
55
+ const count = combined.length;
56
+ const page = combined.slice(offset, offset + limit).map((p) => {
57
+ const posManual = isPosManualPromotion(p);
58
+ const method = p.application_method;
59
+ const methodType = method?.type === "percentage" ? "percentage" : method?.type === "fixed" ? "fixed" : null;
60
+ return {
61
+ id: p.id,
62
+ code: p.code,
63
+ status: p.status,
64
+ origin: posManual ? "pos_manual" : "admin",
65
+ // Admin percentage promos have no rupee amount until applied to a cart.
66
+ amount: posManual
67
+ ? p.metadata?.amount ?? method?.value ?? null
68
+ : methodType === "fixed"
69
+ ? method?.value ?? null
70
+ : null,
71
+ discount_type: posManual ? p.metadata?.discount_type ?? null : methodType,
72
+ discount_value: posManual ? p.metadata?.discount_value ?? null : method?.value ?? null,
73
+ currency_code: p.metadata?.currency_code ?? method?.currency_code ?? null,
74
+ draft_order_id: p.metadata?.draft_order_id ?? null,
75
+ applied_by: posManual ? p.metadata?.applied_by ?? null : "admin",
76
+ applied_at: posManual ? p.metadata?.applied_at ?? p.created_at ?? null : p.created_at ?? null,
77
+ created_at: p.created_at ?? null,
78
+ metadata: p.metadata ?? null,
79
+ };
80
+ });
62
81
  res.json({
63
82
  manual_discounts: page,
64
83
  count,
@@ -73,4 +92,4 @@ async function GET(req, res) {
73
92
  });
74
93
  }
75
94
  }
76
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3Bvcy9tYW51YWwtZGlzY291bnRzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBZ0JBLGtCQStFQztBQTlGRCxxREFBbUQ7QUFFbkQsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFBO0FBUS9COzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsR0FBRyxDQUFDLEdBQWtCLEVBQUUsR0FBbUI7SUFDL0QsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBYyxDQUFBO0lBQzVDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQTtJQUNuRSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3JELE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUU5QyxJQUFJLENBQUM7UUFDSCxNQUFNLGVBQWUsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFPLENBQUMsU0FBUyxDQUsxRCxDQUFBO1FBRUQseUVBQXlFO1FBQ3pFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLEtBQUssR0FBRyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDaEQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sZUFBZSxDQUFDLHNCQUFzQixDQUN6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
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3Bvcy9tYW51YWwtZGlzY291bnRzL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBdUJBLGtCQWdHQztBQXRIRCxxREFBbUQ7QUFFbkQsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFBO0FBVS9CLFNBQVMsb0JBQW9CLENBQUMsQ0FBZTtJQUMzQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUNqQyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxNQUFNLEtBQUssWUFBWSxDQUFBO0FBQzlFLENBQUM7QUFFRDs7OztHQUlHO0FBQ0ksS0FBSyxVQUFVLEdBQUcsQ0FBQyxHQUFrQixFQUFFLEdBQW1CO0lBQy9ELE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQWMsQ0FBQTtJQUM1QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUE7SUFDbkUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUNyRCxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUE7SUFFOUMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxP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
@@ -0,0 +1,66 @@
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.generateDeterministicBarcodeSHA256 = generateDeterministicBarcodeSHA256;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ /**
9
+ * Deterministic EAN-13 Barcode Generator using SHA-256 Hashing.
10
+ * Format: Product Title|Variant Title|Color=White|Size=3-4Y|Weight=200|Width=20|Length=30|Height=2
11
+ *
12
+ * Algorithm Pipeline:
13
+ * Fixed Input String -> SHA-256 -> Numeric Conversion -> 12-Digit Base -> EAN-13 Check Digit -> Final 13-Digit Barcode
14
+ *
15
+ * Output must stay stable: printed labels already carry these values.
16
+ */
17
+ function generateDeterministicBarcodeSHA256(productTitle, variantTitle, options, weight, width, length, height, prefix = "200" // Standard 3-digit in-store retail prefix
18
+ ) {
19
+ const parts = [];
20
+ const pTitle = (productTitle || "").trim();
21
+ if (pTitle)
22
+ parts.push(pTitle);
23
+ const vTitle = (variantTitle || "").trim();
24
+ if (vTitle)
25
+ parts.push(vTitle);
26
+ // Append option attributes (e.g. Color=White|Size=3-4Y)
27
+ if (Array.isArray(options)) {
28
+ options.forEach((opt) => {
29
+ const optTitle = (opt?.option?.title || "").trim();
30
+ const optVal = (opt?.value || "").trim();
31
+ if (optTitle && optVal) {
32
+ parts.push(`${optTitle}=${optVal}`);
33
+ }
34
+ else if (optVal) {
35
+ parts.push(optVal);
36
+ }
37
+ });
38
+ }
39
+ // Append physical attributes if present
40
+ if (weight != null && !isNaN(Number(weight)))
41
+ parts.push(`Weight=${weight}`);
42
+ if (width != null && !isNaN(Number(width)))
43
+ parts.push(`Width=${width}`);
44
+ if (length != null && !isNaN(Number(length)))
45
+ parts.push(`Length=${length}`);
46
+ if (height != null && !isNaN(Number(height)))
47
+ parts.push(`Height=${height}`);
48
+ const inputString = parts.join("|");
49
+ // Step 1: Compute SHA-256 Hash
50
+ const sha256Hex = crypto_1.default.createHash("sha256").update(inputString).digest("hex");
51
+ // Step 2: Convert SHA-256 hash slice to 9-digit numeric payload
52
+ const numericVal = BigInt("0x" + sha256Hex.slice(0, 15));
53
+ const payload9Digits = String(numericVal % 1000000000n).padStart(9, "0");
54
+ // Step 3: Create 12-digit base number (3-digit prefix + 9-digit payload)
55
+ const base12 = `${prefix}${payload9Digits}`;
56
+ // Step 4: Calculate EAN-13 Check Digit
57
+ let sum = 0;
58
+ for (let i = 0; i < 12; i++) {
59
+ const digit = parseInt(base12.charAt(i), 10);
60
+ sum += i % 2 === 0 ? digit : digit * 3;
61
+ }
62
+ const checkDigit = (10 - (sum % 10)) % 10;
63
+ // Step 5: Final 13-digit EAN-13 Barcode
64
+ return `${base12}${checkDigit}`;
65
+ }
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyY29kZS1lYW4xMy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlscy9iYXJjb2RlLWVhbjEzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBZ0JBLGdGQTJEQztBQTNFRCxvREFBMkI7QUFPM0I7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQixrQ0FBa0MsQ0FDaEQsWUFBb0IsRUFDcEIsWUFBb0IsRUFDcEIsT0FBdUMsRUFDdkMsTUFBc0IsRUFDdEIsS0FBcUIsRUFDckIsTUFBc0IsRUFDdEIsTUFBc0IsRUFDdEIsTUFBTSxHQUFHLEtBQUssQ0FBQywwQ0FBMEM7O0lBRXpELE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQTtJQUUxQixNQUFNLE1BQU0sR0FBRyxDQUFDLFlBQVksSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtJQUMxQyxJQUFJLE1BQU07UUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBRTlCLE1BQU0sTUFBTSxHQUFHLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFBO0lBQzFDLElBQUksTUFBTTtRQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUE7SUFFOUIsd0RBQXdEO0lBQ3hELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUN0QixNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFBO1lBQ2xELE1BQU0sTUFBTSxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUN4QyxJQUFJLFFBQVEsSUFBSSxNQUFNLEVBQUUsQ0FBQztn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
@@ -0,0 +1,336 @@
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.HOST_BARCODE_TEMPLATE_PATH = exports.MAX_BARCODE_QTY_PER_VARIANT = void 0;
7
+ exports.clampQty = clampQty;
8
+ exports.parseBarcodePrintBody = parseBarcodePrintBody;
9
+ exports.buildPrintQueue = buildPrintQueue;
10
+ exports.escapeHtml = escapeHtml;
11
+ exports.contactDetailsFromConfig = contactDetailsFromConfig;
12
+ exports.buildContactHtml = buildContactHtml;
13
+ exports.resolvePrices = resolvePrices;
14
+ exports.buildPriceHtml = buildPriceHtml;
15
+ exports.buildOptionsHtml = buildOptionsHtml;
16
+ exports.loadBarcodeTemplate = loadBarcodeTemplate;
17
+ exports.renderBarcodeLabelsHtml = renderBarcodeLabelsHtml;
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const barcode_template_default_1 = require("./barcode-template-default");
21
+ exports.MAX_BARCODE_QTY_PER_VARIANT = 500;
22
+ /** Host override path, relative to the Medusa project root. */
23
+ exports.HOST_BARCODE_TEMPLATE_PATH = path_1.default.join("templates", "barcode-template.html");
24
+ function clampQty(value) {
25
+ const n = Math.floor(Number(value));
26
+ if (!Number.isFinite(n) || n < 1)
27
+ return 1;
28
+ return Math.min(n, exports.MAX_BARCODE_QTY_PER_VARIANT);
29
+ }
30
+ /** Normalises an untrusted request body into the supported print body shape. */
31
+ function parseBarcodePrintBody(raw) {
32
+ if (!raw || typeof raw !== "object")
33
+ return {};
34
+ const body = raw;
35
+ const parsed = {};
36
+ if (Array.isArray(body.items)) {
37
+ parsed.items = body.items
38
+ .filter((item) => !!item && typeof item === "object")
39
+ .filter((item) => typeof item.variant_id === "string" && !!item.variant_id)
40
+ .map((item) => ({
41
+ variant_id: String(item.variant_id),
42
+ quantity: item.quantity === undefined ? undefined : Number(item.quantity),
43
+ }));
44
+ }
45
+ if (Array.isArray(body.variant_ids)) {
46
+ parsed.variant_ids = body.variant_ids.filter((id) => typeof id === "string" && !!id);
47
+ }
48
+ if (typeof body.region_id === "string")
49
+ parsed.region_id = body.region_id;
50
+ if (body.print_width !== undefined)
51
+ parsed.print_width = Number(body.print_width);
52
+ if (body.print_height !== undefined) {
53
+ parsed.print_height = Number(body.print_height);
54
+ }
55
+ return parsed;
56
+ }
57
+ /** Expand items/ids into an ordered list of variant ids (with repeats for qty). */
58
+ function buildPrintQueue(body) {
59
+ if (Array.isArray(body.items) && body.items.length > 0) {
60
+ const queue = [];
61
+ for (const item of body.items) {
62
+ if (!item?.variant_id)
63
+ continue;
64
+ const qty = clampQty(item.quantity);
65
+ for (let i = 0; i < qty; i++)
66
+ queue.push(item.variant_id);
67
+ }
68
+ return queue;
69
+ }
70
+ return Array.isArray(body.variant_ids) ? body.variant_ids.filter(Boolean) : [];
71
+ }
72
+ function takeAmount(value) {
73
+ const n = Number(value);
74
+ return Number.isFinite(n) && n > 0 ? n : 0;
75
+ }
76
+ function escapeHtml(value) {
77
+ return value
78
+ .replace(/&/g, "&amp;")
79
+ .replace(/</g, "&lt;")
80
+ .replace(/>/g, "&gt;")
81
+ .replace(/"/g, "&quot;");
82
+ }
83
+ /** Reads phone/email/address from dynamic config values (keys containing contact-*). */
84
+ function contactDetailsFromConfig(values) {
85
+ const contactDetails = { phone: "", email: "", address: "" };
86
+ for (const [key, val] of Object.entries(values)) {
87
+ if (key.includes("contact-phone"))
88
+ contactDetails.phone = String(val || "");
89
+ if (key.includes("contact-email"))
90
+ contactDetails.email = String(val || "");
91
+ if (key.includes("contact-address"))
92
+ contactDetails.address = String(val || "");
93
+ }
94
+ return contactDetails;
95
+ }
96
+ function buildContactHtml(contact) {
97
+ const rows = [];
98
+ rows.push(`<div class="info-row info-row-inline"><span class="info-inline">Country Of Origin India</span></div>`);
99
+ if (contact.address) {
100
+ rows.push(`<div class="info-row info-row-address"><span class="info-label info-label-mixed">Manufactured &amp; Marketed by</span><span class="info-value">${escapeHtml(contact.address)}</span></div>`);
101
+ }
102
+ if (contact.email || contact.phone) {
103
+ const lines = [
104
+ `<span class="complaints-title">For Customer Complaints:</span>`,
105
+ ];
106
+ if (contact.email) {
107
+ lines.push(`<span class="complaints-line contact-email">${escapeHtml(contact.email)}</span>`);
108
+ }
109
+ if (contact.phone) {
110
+ lines.push(`<span class="complaints-line">${escapeHtml(contact.phone)}</span>`);
111
+ }
112
+ rows.push(`<div class="info-row complaints-block">${lines.join("")}</div>`);
113
+ }
114
+ return rows.join("");
115
+ }
116
+ function resolvePrices(variant) {
117
+ const calc = variant.calculated_price;
118
+ const original = takeAmount(calc?.original_amount);
119
+ const current = takeAmount(calc?.calculated_amount);
120
+ if (original > 0 && current > 0 && current < original) {
121
+ return { mrp: original, sale: current };
122
+ }
123
+ const prices = variant.price_set?.prices || [];
124
+ const inr = prices.filter((p) => (p.currency_code || "").toLowerCase() === "inr");
125
+ const pool = inr.length > 0 ? inr : prices;
126
+ const baseAmounts = pool
127
+ .filter((p) => !p.price_list_id)
128
+ .map((p) => takeAmount(p.amount))
129
+ .filter(Boolean);
130
+ const listAmounts = pool
131
+ .filter((p) => !!p.price_list_id)
132
+ .map((p) => takeAmount(p.amount))
133
+ .filter(Boolean);
134
+ let mrp = original || current || (baseAmounts.length ? Math.max(...baseAmounts) : 0);
135
+ let sale = listAmounts.length ? Math.min(...listAmounts) : 0;
136
+ if (!sale && baseAmounts.length >= 2) {
137
+ const minBase = Math.min(...baseAmounts);
138
+ const maxBase = Math.max(...baseAmounts);
139
+ if (minBase < maxBase) {
140
+ mrp = maxBase;
141
+ sale = minBase;
142
+ }
143
+ }
144
+ if (sale > 0 && mrp > 0 && sale < mrp) {
145
+ return { mrp, sale };
146
+ }
147
+ return { mrp: mrp || sale || 0, sale: 0 };
148
+ }
149
+ function buildPriceHtml(mrp, sale) {
150
+ if (sale > 0 && mrp > 0 && sale < mrp) {
151
+ return [
152
+ `<span class="price-label">Maximum Retail Price</span>`,
153
+ `<div class="price-row">`,
154
+ `<div class="mrp-crossed">₹&nbsp;${mrp}</div>`,
155
+ `<div class="sale-price">₹&nbsp;${sale}</div>`,
156
+ `</div>`,
157
+ ].join("");
158
+ }
159
+ if (mrp > 0) {
160
+ return [
161
+ `<span class="price-label">Maximum Retail Price</span>`,
162
+ `<div class="mrp-only">₹&nbsp;${mrp}</div>`,
163
+ ].join("");
164
+ }
165
+ return `<div class="mrp-only">₹&nbsp;0</div>`;
166
+ }
167
+ function buildOptionsHtml(variant) {
168
+ return (variant.options || [])
169
+ .map((o) => {
170
+ const optionTitle = o.option?.title || o.title || "Option";
171
+ const value = (o.value || "").toUpperCase();
172
+ return `<div class="option-line"><span class="option-label">${escapeHtml(optionTitle)}:</span><span class="option-value">${escapeHtml(value)}</span></div>`;
173
+ })
174
+ .join("");
175
+ }
176
+ /** Host file `templates/barcode-template.html` wins; otherwise the bundled default. */
177
+ function loadBarcodeTemplate(cwd = process.cwd()) {
178
+ const hostPath = path_1.default.join(cwd, exports.HOST_BARCODE_TEMPLATE_PATH);
179
+ try {
180
+ if (fs_1.default.existsSync(hostPath)) {
181
+ return fs_1.default.readFileSync(hostPath, "utf-8");
182
+ }
183
+ }
184
+ catch {
185
+ // Unreadable host override — fall back to the bundled template
186
+ }
187
+ return barcode_template_default_1.DEFAULT_BARCODE_TEMPLATE_HTML;
188
+ }
189
+ function buildPrintScript(barcodesList, printWidth, printHeight) {
190
+ return `
191
+ <script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
192
+ <script>
193
+ const barcodes = ${JSON.stringify(barcodesList)};
194
+ const BAR_MODULE_WIDTH = ${Math.max(1.5, printWidth)};
195
+ const BAR_HEIGHT = ${Math.max(40, printHeight)};
196
+
197
+ function drawBarcodes() {
198
+ if (typeof JsBarcode !== 'function') {
199
+ throw new Error('JsBarcode failed to load');
200
+ }
201
+
202
+ // Draw barcode horizontal (no CSS rotate) — natural CODE128 orientation.
203
+ // Keep module ratios intact (no stretch) so scanners can read.
204
+ barcodes.forEach((item) => {
205
+ const host = document.getElementById('barcode-' + item.svgId);
206
+ if (!host) return;
207
+ try {
208
+ // Always treat as string — avoids scientific notation like 1.6013E+12
209
+ const code = String(item.value == null ? '' : item.value);
210
+ const canvas = document.createElement('canvas');
211
+ JsBarcode(canvas, code, {
212
+ format: 'CODE128',
213
+ lineColor: '#000000',
214
+ background: '#ffffff',
215
+ width: Math.max(2, BAR_MODULE_WIDTH),
216
+ height: Math.max(48, BAR_HEIGHT),
217
+ displayValue: true,
218
+ text: code,
219
+ font: 'Arial',
220
+ fontOptions: 'bold',
221
+ fontSize: 12,
222
+ textAlign: 'center',
223
+ textPosition: 'bottom',
224
+ textMargin: 2,
225
+ margin: 3,
226
+ marginTop: 2,
227
+ marginBottom: 2,
228
+ });
229
+
230
+ const img = document.createElement('img');
231
+ img.className = 'barcode-img';
232
+ img.alt = code;
233
+ img.src = canvas.toDataURL('image/png');
234
+ img.style.width = '1.55in';
235
+ img.style.height = 'auto';
236
+ img.style.maxWidth = '1.55in';
237
+ img.style.maxHeight = '0.62in';
238
+ img.style.objectFit = 'contain';
239
+ img.style.imageRendering = 'pixelated';
240
+ img.style.display = 'block';
241
+ host.replaceWith(img);
242
+ } catch (e) {
243
+ console.error('Invalid barcode format:', item.value, e);
244
+ }
245
+ });
246
+ }
247
+
248
+ function waitFrames(n) {
249
+ return new Promise((resolve) => {
250
+ const step = () => {
251
+ if (n <= 0) return resolve();
252
+ n -= 1;
253
+ requestAnimationFrame(step);
254
+ };
255
+ step();
256
+ });
257
+ }
258
+
259
+ function waitForJsBarcode(timeoutMs) {
260
+ const start = Date.now();
261
+ return new Promise((resolve, reject) => {
262
+ const tick = () => {
263
+ if (typeof JsBarcode === 'function') return resolve();
264
+ if (Date.now() - start > timeoutMs) {
265
+ return reject(new Error('JsBarcode load timeout'));
266
+ }
267
+ setTimeout(tick, 50);
268
+ };
269
+ tick();
270
+ });
271
+ }
272
+
273
+ async function startPrint() {
274
+ try {
275
+ await waitForJsBarcode(8000);
276
+ drawBarcodes();
277
+ // Let images decode before opening the print dialog
278
+ await waitFrames(2);
279
+ await new Promise((r) => setTimeout(r, 300));
280
+ const imgs = Array.from(document.querySelectorAll('img.barcode-img'));
281
+ await Promise.all(
282
+ imgs.map((img) =>
283
+ img.decode ? img.decode().catch(() => {}) : Promise.resolve()
284
+ )
285
+ );
286
+ window.focus();
287
+ window.print();
288
+ } catch (e) {
289
+ console.error('Print prep failed:', e);
290
+ window.print();
291
+ }
292
+ }
293
+
294
+ if (document.readyState === 'complete') {
295
+ startPrint();
296
+ } else {
297
+ window.addEventListener('load', startPrint);
298
+ }
299
+ </script>
300
+ </body>`;
301
+ }
302
+ /**
303
+ * Fills the template with one tag per variant (repeats allowed for quantity)
304
+ * and appends the JsBarcode draw + auto-print script. SVG ids are unique per copy.
305
+ */
306
+ function renderBarcodeLabelsHtml(input) {
307
+ const templateMatch = input.template.match(/<template id="single-tag">([\s\S]*?)<\/template>/);
308
+ const singleTagHtml = templateMatch ? templateMatch[1] : "";
309
+ const barcodesList = [];
310
+ const tagsHtml = input.variants
311
+ .map((variant, index) => {
312
+ const barcodeValue = String(variant.barcode || variant.id || "");
313
+ const svgId = `bc${index}`;
314
+ barcodesList.push({ svgId, value: barcodeValue });
315
+ const { mrp, sale } = resolvePrices(variant);
316
+ const skuHtml = variant.sku
317
+ ? `<div class="sku-inline">SKU: ${escapeHtml(variant.sku)}</div>`
318
+ : "";
319
+ return singleTagHtml
320
+ .replace(/{{PRODUCT_NAME}}/g, escapeHtml(variant.product?.title || "Product"))
321
+ .replace(/{{OPTIONS_HTML}}/g, buildOptionsHtml(variant))
322
+ .replace(/{{SKU_HTML}}/g, skuHtml)
323
+ .replace(/{{PRICE_HTML}}/g, buildPriceHtml(mrp, sale))
324
+ .replace(/{{CONTACT_DETAILS}}/g, input.contactHtml)
325
+ .replace(/{{BARCODE_SVG_ID}}/g, svgId)
326
+ .replace(/{{BARCODE_ID}}/g, escapeHtml(barcodeValue));
327
+ })
328
+ .join("\n");
329
+ let html = input.template.replace("{{ALL_TAGS_HTML}}", tagsHtml);
330
+ html = html.replace("</head>", `
331
+ <title>Barcode Labels</title>
332
+ </head>`);
333
+ html = html.replace("</body>", buildPrintScript(barcodesList, input.printWidth, input.printHeight));
334
+ return { html, count: input.variants.length };
335
+ }
336
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyY29kZS1sYWJlbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvYmFyY29kZS1sYWJlbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBdURBLDRCQUlDO0FBR0Qsc0RBNEJDO0FBR0QsMENBV0M7QUFPRCxnQ0FNQztBQUdELDREQVVDO0FBRUQsNENBK0JDO0FBRUQsc0NBMENDO0FBRUQsd0NBaUJDO0FBRUQsNENBVUM7QUFHRCxrREFVQztBQTRIRCwwREFxREM7QUE1YUQsNENBQW1CO0FBQ25CLGdEQUF1QjtBQUN2Qix5RUFBMEU7QUE2QzdELFFBQUEsMkJBQTJCLEdBQUcsR0FBRyxDQUFBO0FBRTlDLCtEQUErRDtBQUNsRCxRQUFBLDBCQUEwQixHQUFHLGNBQUksQ0FBQyxJQUFJLENBQ2pELFdBQVcsRUFDWCx1QkFBdUIsQ0FDeEIsQ0FBQTtBQUVELFNBQWdCLFFBQVEsQ0FBQyxLQUFjO0lBQ3JDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7SUFDbkMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7UUFBRSxPQUFPLENBQUMsQ0FBQTtJQUMxQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLG1DQUEyQixDQUFDLENBQUE7QUFDakQsQ0FBQztBQUVELGdGQUFnRjtBQUNoRixTQUFnQixxQkFBcUIsQ0FBQyxHQUFZO0lBQ2hELElBQUksQ0FBQyxHQUFHLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUTtRQUFFLE9BQU8sRUFBRSxDQUFBO0lBQzlDLE1BQU0sSUFBSSxHQUFHLEdBQThCLENBQUE7SUFDM0MsTUFBTSxNQUFNLEdBQXFCLEVBQUUsQ0FBQTtJQUVuQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxF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
@@ -0,0 +1,434 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_BARCODE_TEMPLATE_HTML = void 0;
4
+ /**
5
+ * Default 2in x 3in hang-tag label. Placeholders: {{ALL_TAGS_HTML}} plus, inside
6
+ * <template id="single-tag">, {{PRODUCT_NAME}} {{OPTIONS_HTML}} {{SKU_HTML}} {{PRICE_HTML}}
7
+ * {{CONTACT_DETAILS}} {{BARCODE_SVG_ID}}. Hosts override via templates/barcode-template.html.
8
+ */
9
+ exports.DEFAULT_BARCODE_TEMPLATE_HTML = `<!DOCTYPE html>
10
+ <html>
11
+ <head>
12
+ <meta charset="UTF-8" />
13
+ <style>
14
+ /*
15
+ Hang-tag portrait 2in × 3in — compact spacing so all details fit.
16
+ Top: product + options
17
+ Mid: price, then horizontal barcode centered
18
+ Bottom: country / warehouse / contact + star
19
+ */
20
+ * { box-sizing: border-box; }
21
+
22
+ html, body {
23
+ font-family: Arial, Helvetica, sans-serif;
24
+ margin: 0;
25
+ padding: 0;
26
+ background: #fff;
27
+ }
28
+
29
+ .tags-wrapper {
30
+ display: block;
31
+ margin: 0;
32
+ padding: 0;
33
+ }
34
+
35
+ .print-sheet {
36
+ display: block;
37
+ width: 2in;
38
+ height: 3in;
39
+ margin: 0;
40
+ padding: 0;
41
+ overflow: hidden;
42
+ position: relative;
43
+ background: #fff;
44
+ page-break-after: always;
45
+ break-after: page;
46
+ page-break-inside: avoid;
47
+ break-inside: avoid;
48
+ }
49
+ .print-sheet:last-child {
50
+ page-break-after: auto;
51
+ break-after: auto;
52
+ }
53
+
54
+ .tag-container,
55
+ .tag-clip {
56
+ position: relative;
57
+ width: 2in;
58
+ height: 3in;
59
+ margin: 0;
60
+ padding: 0;
61
+ overflow: hidden;
62
+ background: #fff;
63
+ }
64
+
65
+ @media screen {
66
+ html, body { background: #e8e8e8; }
67
+ .tags-wrapper { padding: 12px; }
68
+ .print-sheet {
69
+ margin: 0 0 12px 0;
70
+ border: 1px solid #bbb;
71
+ page-break-after: auto;
72
+ break-after: auto;
73
+ }
74
+ }
75
+
76
+ @media print {
77
+ @page {
78
+ margin: 0 !important;
79
+ size: 2in 3in;
80
+ }
81
+ html, body {
82
+ margin: 0 !important;
83
+ padding: 0 !important;
84
+ width: 2in !important;
85
+ background: #fff !important;
86
+ -webkit-print-color-adjust: exact;
87
+ print-color-adjust: exact;
88
+ }
89
+ .tags-wrapper {
90
+ display: block !important;
91
+ margin: 0 !important;
92
+ padding: 0 !important;
93
+ }
94
+ .print-sheet {
95
+ display: block !important;
96
+ width: 2in !important;
97
+ height: 3in !important;
98
+ margin: 0 !important;
99
+ border: none !important;
100
+ overflow: hidden !important;
101
+ page-break-after: always !important;
102
+ break-after: page !important;
103
+ page-break-inside: avoid !important;
104
+ break-inside: avoid !important;
105
+ }
106
+ .print-sheet:last-child {
107
+ page-break-after: auto !important;
108
+ break-after: auto !important;
109
+ }
110
+ .tag-container,
111
+ .tag-clip {
112
+ width: 2in !important;
113
+ height: 3in !important;
114
+ overflow: hidden !important;
115
+ }
116
+ .mrp-crossed,
117
+ .sale-price,
118
+ .mrp-only,
119
+ .price-label {
120
+ color: #000 !important;
121
+ -webkit-print-color-adjust: exact !important;
122
+ print-color-adjust: exact !important;
123
+ }
124
+ .mrp-crossed {
125
+ text-decoration: line-through !important;
126
+ text-decoration-color: #000 !important;
127
+ }
128
+ }
129
+
130
+ .tag-layout {
131
+ display: flex;
132
+ flex-direction: column;
133
+ width: 2in;
134
+ height: 3in;
135
+ /* Extra left padding — thermal printers clip sticker left edge */
136
+ padding: 0.08in 0.08in 0.10in 0.20in;
137
+ gap: 0;
138
+ }
139
+
140
+ .tag-header {
141
+ flex: 0 0 auto;
142
+ margin: 0 0 0.035in 0;
143
+ }
144
+
145
+ .product-name {
146
+ font-size: 10px;
147
+ font-weight: 800;
148
+ text-transform: uppercase;
149
+ line-height: 1.12;
150
+ word-break: break-word;
151
+ margin: 0 0 0.025in 0;
152
+ display: block;
153
+ color: #000;
154
+ }
155
+ .option-line {
156
+ display: grid;
157
+ grid-template-columns: 0.48in auto;
158
+ column-gap: 0.08em;
159
+ align-items: baseline;
160
+ font-size: 8.5px;
161
+ font-weight: 700;
162
+ text-transform: uppercase;
163
+ line-height: 1.15;
164
+ margin: 0.01in 0 0 0;
165
+ color: #000;
166
+ }
167
+ .option-label {
168
+ font-weight: 400;
169
+ color: #333;
170
+ text-align: left;
171
+ white-space: nowrap;
172
+ }
173
+ .option-colon {
174
+ display: none;
175
+ }
176
+ .option-value {
177
+ font-weight: 700;
178
+ color: #000;
179
+ min-width: 0;
180
+ }
181
+ .sku-inline {
182
+ font-size: 7px;
183
+ color: #333;
184
+ text-transform: uppercase;
185
+ line-height: 1.1;
186
+ display: block;
187
+ margin-top: 0.02in;
188
+ }
189
+
190
+ /* Price tight under options */
191
+ .tag-price {
192
+ flex: 0 0 auto;
193
+ margin: 0 0 0.035in 0;
194
+ max-width: 100%;
195
+ }
196
+
197
+ .price-label {
198
+ font-size: 7px;
199
+ color: #000;
200
+ text-transform: uppercase;
201
+ display: block;
202
+ line-height: 1.1;
203
+ margin-top: 0.03in;
204
+ font-weight: 700;
205
+ letter-spacing: 0.01em;
206
+ }
207
+ .price-label:first-child { margin-top: 0; }
208
+
209
+ .price-row {
210
+ display: flex;
211
+ flex-direction: row;
212
+ align-items: baseline;
213
+ justify-content: flex-start;
214
+ gap: 0.12in;
215
+ margin-top: 0.02in;
216
+ }
217
+ .mrp-crossed {
218
+ font-size: 15px;
219
+ font-weight: 800;
220
+ color: #000 !important;
221
+ display: inline-block;
222
+ line-height: 1.1;
223
+ position: relative;
224
+ text-decoration: line-through;
225
+ text-decoration-color: #000;
226
+ text-decoration-thickness: 1.5px;
227
+ flex: 0 0 auto;
228
+ }
229
+ .mrp-crossed::after {
230
+ content: "";
231
+ position: absolute;
232
+ left: 0;
233
+ right: 0;
234
+ top: 50%;
235
+ border-top: 1.5px solid #000;
236
+ transform: translateY(-50%);
237
+ }
238
+ .sale-price,
239
+ .mrp-only {
240
+ font-size: 15px;
241
+ font-weight: 800;
242
+ color: #000 !important;
243
+ line-height: 1.05;
244
+ display: block;
245
+ margin-top: 0;
246
+ flex: 0 0 auto;
247
+ }
248
+ .mrp-only {
249
+ margin-top: 0.02in;
250
+ font-size: 17px;
251
+ font-weight: 900;
252
+ }
253
+ .tax-note {
254
+ font-size: 6px;
255
+ color: #000;
256
+ display: block;
257
+ line-height: 1.1;
258
+ margin-top: 0.025in;
259
+ }
260
+
261
+ /* Horizontal barcode centered across the tag width */
262
+ .tag-barcode-rail {
263
+ flex: 0 0 auto;
264
+ width: 100%;
265
+ height: 0.66in;
266
+ position: relative;
267
+ display: flex;
268
+ align-items: center;
269
+ justify-content: center;
270
+ overflow: hidden;
271
+ margin: 0.02in 0 0.05in 0;
272
+ }
273
+ .tag-barcode-rail .barcode-rotate {
274
+ display: block;
275
+ transform: none;
276
+ -webkit-transform: none;
277
+ }
278
+ .tag-barcode-rail canvas,
279
+ .tag-barcode-rail .barcode-img {
280
+ display: block;
281
+ width: 1.55in !important;
282
+ height: auto !important;
283
+ max-width: 1.55in;
284
+ max-height: 0.62in;
285
+ image-rendering: pixelated;
286
+ }
287
+
288
+ /* Footer takes remaining space so warehouse/contact stay visible */
289
+ .tag-footer {
290
+ flex: 1 1 auto;
291
+ min-height: 0;
292
+ display: flex;
293
+ flex-direction: row;
294
+ align-items: flex-start;
295
+ justify-content: space-between;
296
+ gap: 0.04in;
297
+ overflow: hidden;
298
+ margin-top: 0;
299
+ }
300
+
301
+ .tag-footer-info {
302
+ flex: 1 1 auto;
303
+ min-width: 0;
304
+ overflow: hidden;
305
+ }
306
+
307
+ .info-label {
308
+ font-size: 7px;
309
+ font-weight: 700;
310
+ text-transform: uppercase;
311
+ color: #000;
312
+ display: block;
313
+ margin-bottom: 0.01in;
314
+ line-height: 1.1;
315
+ }
316
+ .info-label-mixed {
317
+ text-transform: none;
318
+ }
319
+ .info-value {
320
+ font-size: 7px;
321
+ font-weight: 600;
322
+ color: #000;
323
+ line-height: 1.2;
324
+ display: block;
325
+ word-break: break-word;
326
+ text-transform: uppercase;
327
+ }
328
+ .info-value .contact-email {
329
+ text-transform: none;
330
+ font-weight: 600;
331
+ letter-spacing: 0;
332
+ }
333
+ .info-inline {
334
+ display: block;
335
+ font-size: 7px;
336
+ font-weight: 700;
337
+ text-transform: uppercase;
338
+ color: #000;
339
+ line-height: 1.15;
340
+ }
341
+ .info-row-address {
342
+ margin-bottom: 0;
343
+ }
344
+ .complaints-block {
345
+ /* ~1 enter gap after address (SURAT line) */
346
+ margin-top: 0.14in;
347
+ }
348
+ .complaints-title {
349
+ display: block;
350
+ font-size: 7px;
351
+ font-weight: 600;
352
+ font-style: italic;
353
+ color: #000;
354
+ line-height: 1.15;
355
+ margin-bottom: 0.01in;
356
+ text-transform: none;
357
+ }
358
+ .complaints-line {
359
+ display: block;
360
+ font-size: 7px;
361
+ font-weight: 600;
362
+ color: #000;
363
+ line-height: 1.2;
364
+ word-break: break-word;
365
+ }
366
+ .complaints-line.contact-email {
367
+ text-transform: none;
368
+ letter-spacing: 0;
369
+ }
370
+ .info-row {
371
+ display: block;
372
+ margin-bottom: 0.03in;
373
+ }
374
+ .info-row:last-child { margin-bottom: 0; }
375
+
376
+ .tag-star {
377
+ flex: 0 0 auto;
378
+ width: 0.22in;
379
+ height: 0.22in;
380
+ background: #000;
381
+ color: #fff;
382
+ display: flex;
383
+ align-items: center;
384
+ justify-content: center;
385
+ font-size: 12px;
386
+ font-weight: 900;
387
+ line-height: 1;
388
+ margin-top: 0.01in;
389
+ align-self: flex-end;
390
+ }
391
+ </style>
392
+ </head>
393
+ <body>
394
+ <div class="tags-wrapper">
395
+ {{ALL_TAGS_HTML}}
396
+ </div>
397
+
398
+ <template id="single-tag">
399
+ <div class="print-sheet">
400
+ <div class="tag-container">
401
+ <div class="tag-clip">
402
+ <div class="tag-layout">
403
+ <div class="tag-header">
404
+ <div class="product-name">{{PRODUCT_NAME}}</div>
405
+ {{OPTIONS_HTML}}
406
+ {{SKU_HTML}}
407
+ </div>
408
+
409
+ <div class="tag-price">
410
+ {{PRICE_HTML}}
411
+ <span class="tax-note">Inclusive of all taxes</span>
412
+ </div>
413
+
414
+ <div class="tag-barcode-rail">
415
+ <div class="barcode-rotate">
416
+ <canvas id="barcode-{{BARCODE_SVG_ID}}"></canvas>
417
+ </div>
418
+ </div>
419
+
420
+ <div class="tag-footer">
421
+ <div class="tag-footer-info">
422
+ {{CONTACT_DETAILS}}
423
+ </div>
424
+ <div class="tag-star" aria-hidden="true">✦</div>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ </div>
429
+ </div>
430
+ </template>
431
+ </body>
432
+ </html>
433
+ `;
434
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyY29kZS10ZW1wbGF0ZS1kZWZhdWx0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2JhcmNvZGUtdGVtcGxhdGUtZGVmYXVsdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7OztHQUlHO0FBQ1UsUUFBQSw2QkFBNkIsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztDQXdhNUMsQ0FBQSJ9
package/README.md CHANGED
@@ -93,6 +93,36 @@ Successful POS returns set `metadata.pos_returned` / `pos_returned_at`. Cancel s
93
93
 
94
94
  **Gift card refund** issues a **new** gift card for the refund amount (`expiresAt: null`). Registered customers get `assignedCustomerId`; walk-in/guest sales leave the card unassigned. POS prints a slip with the code after confirm. Order metadata stores `pos_refund_method`, `pos_gift_card_code`, and `pos_gift_card_amount` so Order Details can reprint the slip.
95
95
 
96
+ ## Barcode labels (0.0.35+)
97
+
98
+ | Method | Path | Purpose |
99
+ |--------|------|---------|
100
+ | POST | `/admin/barcode-template` | Ready-to-print label HTML for variants |
101
+ | GET | `/admin/barcode-template` | Raw template + contact details (preview) |
102
+ | POST | `/admin/barcodes/bulk-generate` | Write deterministic EAN-13 barcodes onto variants |
103
+
104
+ **`POST /admin/barcode-template`**
105
+
106
+ ```json
107
+ { "items": [{ "variant_id": "variant_1", "quantity": 5 }], "region_id": "reg_1", "print_width": 2, "print_height": 60 }
108
+ ```
109
+
110
+ Legacy `{ "variant_ids": ["variant_1"] }` still works (one label each). Quantity is capped at 500 per variant. `region_id` is optional; without it the INR region (or the first region) is used for `calculated_price`. Returns `{ html, count, variants }`. The HTML draws CODE128 barcodes with JsBarcode (loaded from jsDelivr) and opens the print dialog. Errors: `400` (no items), `404` (no variants found), `500` with `{ error }`.
111
+
112
+ **`POST /admin/barcodes/bulk-generate`** — body `{ "variantIds": ["variant_1"] }`. Builds `Product|Variant|Option=Value|Weight=…|Width=…|Length=…|Height=…`, hashes it with SHA-256 and turns it into a 13-digit EAN with prefix `200`. The same input always gives the same barcode. Returns `{ success, message, count }`.
113
+
114
+ **Template.** The plugin bundles a 2in × 3in hang-tag template. To use your own, put `templates/barcode-template.html` in the Medusa project root; it takes priority. It must contain `{{ALL_TAGS_HTML}}` and a `<template id="single-tag">` with `{{PRODUCT_NAME}}`, `{{OPTIONS_HTML}}`, `{{SKU_HTML}}`, `{{PRICE_HTML}}`, `{{CONTACT_DETAILS}}` and a `<canvas id="barcode-{{BARCODE_SVG_ID}}">`.
115
+
116
+ **Contact block.** If the `dynamic_config` service (medusa-plugin-dynamic-config) is registered, values whose keys contain `contact-phone`, `contact-email` and `contact-address` fill the footer. Without it the footer shows only "Country Of Origin India".
117
+
118
+ POS staff access follows the existing guard: both paths are manager-write, so cashier sessions cannot POST to them (print or generate). For managers, a `region_id` in the print body must match the till's assigned region.
119
+
120
+ ## Known Issues & Fixes
121
+
122
+ ### 0.0.35 — barcode routes moved from the Chocomelon host
123
+
124
+ `/admin/barcode-template` and `/admin/barcodes/bulk-generate` used to live in the Chocomelon store (`src/api/admin/...` plus `templates/barcode-template.html`). They now ship with this plugin with the same request/response shapes, so the `medusa-pos` client needs no change. **Delete the host copies after upgrading** — Medusa project routes override plugin routes, so stale host files would keep serving the old code. EAN-13 output is unchanged; existing printed labels still scan to the same variants.
125
+
96
126
  ## Build
97
127
 
98
128
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-pos-plugin",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "Medusa v2 POS operations: draft carts, finalize, payments, returns, catalog, refunds.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",