@zaamx/netme-bundle 0.0.6 → 0.0.8

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,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SPECIAL_PACK_CATEGORY_ID = exports.BUNDLE_MODULE = void 0;
4
+ var bundles_1 = require("../../../modules/bundles");
5
+ Object.defineProperty(exports, "BUNDLE_MODULE", { enumerable: true, get: function () { return bundles_1.BUNDLE_MODULE; } });
6
+ var service_1 = require("../../../modules/bundles/service");
7
+ Object.defineProperty(exports, "SPECIAL_PACK_CATEGORY_ID", { enumerable: true, get: function () { return service_1.SPECIAL_PACK_CATEGORY_ID; } });
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwaS9zdG9yZS9zcGVjaWFsLXBhY2tzL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxvREFBd0Q7QUFBL0Msd0dBQUEsYUFBYSxPQUFBO0FBQ3RCLDREQUEyRTtBQUFsRSxtSEFBQSx3QkFBd0IsT0FBQSJ9
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * GET /store/special-packs
4
+ *
5
+ * Devuelve cuántos Paquetes a Precio Especial tiene disponibles
6
+ * el usuario autenticado.
7
+ *
8
+ * Usado por el storefront para:
9
+ * - Mostrar el contador de paquetes disponibles
10
+ * - Activar/desactivar el botón "Add to Cart" en esos productos
11
+ *
12
+ * Requiere: customer autenticado (Bearer token con actor_id poblado)
13
+ *
14
+ * Respuesta 200:
15
+ * { available: number, packs: SpecialPackCredit[] }
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GET = GET;
19
+ const bundles_1 = require("../../../modules/bundles");
20
+ async function GET(req, res) {
21
+ const customerId = req.auth_context?.actor_id;
22
+ if (!customerId) {
23
+ res.status(401).json({ error: "No autenticado" });
24
+ return;
25
+ }
26
+ try {
27
+ // Resolver netme_profile_id del customer via la link table
28
+ const bundleService = req.scope.resolve(bundles_1.BUNDLE_MODULE);
29
+ const packs = await bundleService.getAvailableSpecialPacks(customerId);
30
+ res.status(200).json({
31
+ available: packs.length,
32
+ packs,
33
+ });
34
+ }
35
+ catch (error) {
36
+ console.error("[special-packs] Error:", error);
37
+ res.status(500).json({ error: "Error al consultar paquetes disponibles" });
38
+ }
39
+ }
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL3NwZWNpYWwtcGFja3Mvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7OztHQWNHOztBQW9CSCxrQkF3QkM7QUF6Q0Qsc0RBQXdEO0FBaUJqRCxLQUFLLFVBQVUsR0FBRyxDQUN2QixHQUErQixFQUMvQixHQUFtQjtJQUVuQixNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQTtJQUU3QyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFBO1FBQ2pELE9BQU07SUFDUixDQUFDO0lBRUQsSUFBSSxDQUFDO1FBQ0gsMkRBQTJEO1FBQzNELE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLHVCQUFhLENBQWtCLENBQUE7UUFDdkUsTUFBTSxLQUFLLEdBQUcsTUFBTSxhQUFhLENBQUMsd0JBQXdCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFdEUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbkIsU0FBUyxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3ZCLEtBQUs7U0FDTixDQUFDLENBQUE7SUFDSixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsd0JBQXdCLEVBQUUsS0FBSyxDQUFDLENBQUE7UUFDOUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUseUNBQXlDLEVBQUUsQ0FBQyxDQUFBO0lBQzVFLENBQUM7QUFDSCxDQUFDIn0=
@@ -1,17 +1,203 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SPECIAL_PACK_CATEGORY_ID = void 0;
3
16
  const utils_1 = require("@medusajs/framework/utils");
4
17
  const bundle_1 = require("./models/bundle");
18
+ // Categoría de Paquetes a Precio Especial en Medusa
19
+ exports.SPECIAL_PACK_CATEGORY_ID = "pcat_01KQDWQ1GCQR1F278TMVWY9WNB";
5
20
  class BundleService extends (0, utils_1.MedusaService)({
6
21
  Bundle: bundle_1.Bundle,
7
22
  }) {
8
23
  async attachBundleToProduct(productId) {
9
24
  const bundle = await this.listBundles({
10
25
  id: [productId],
11
- relations: ['childProducts']
26
+ relations: ["childProducts"],
12
27
  });
13
28
  return bundle[0] || null;
14
29
  }
30
+ // ── Paquetes a Precio Especial ────────────────────────────
31
+ /**
32
+ * Obtiene el netme_profile_id de un customer de Medusa
33
+ * vía la link table customer_customer_netmemodule_netme_profile.
34
+ */
35
+ async getProfileIdFromCustomer(customerId) {
36
+ return this._getProfileIdFromCustomer(customerId);
37
+ }
38
+ async _getProfileIdFromCustomer(customerId, sharedContext) {
39
+ const rows = await sharedContext?.manager?.execute(`SELECT netme_profile_id::INTEGER AS profile_id
40
+ FROM customer_customer_netmemodule_netme_profile
41
+ WHERE customer_id = ?
42
+ AND deleted_at IS NULL
43
+ LIMIT 1`, [customerId]);
44
+ return rows?.[0]?.profile_id ?? null;
45
+ }
46
+ /**
47
+ * Devuelve los paquetes disponibles de un customer.
48
+ * Convierte customer_id → netme_profile_id y consulta netme_special_pack_credits.
49
+ */
50
+ async getAvailableSpecialPacks(customerId) {
51
+ const profileId = await this.getProfileIdFromCustomer(customerId);
52
+ if (!profileId)
53
+ return [];
54
+ return this._getAvailableSpecialPacks(profileId);
55
+ }
56
+ async _getAvailableSpecialPacks(profileId, sharedContext) {
57
+ const rows = await sharedContext?.manager?.execute(`SELECT id, periods_id, calc_date,
58
+ client_1_id, client_2_id, client_3_id,
59
+ client_1_qv, client_2_qv, client_3_qv,
60
+ status, medusa_order_id, redeemed_at, created_at
61
+ FROM netme_special_pack_credits
62
+ WHERE profile_id = ?
63
+ AND status = 'available'
64
+ ORDER BY created_at ASC`, [profileId]);
65
+ return rows ?? [];
66
+ }
67
+ /**
68
+ * Verifica si un customer puede comprar paquetes a precio especial.
69
+ * Usa COUNT directo — no carga todos los packs innecesariamente.
70
+ */
71
+ async canPurchaseSpecialPack(customerId) {
72
+ const profileId = await this.getProfileIdFromCustomer(customerId);
73
+ if (!profileId)
74
+ return false;
75
+ return this._canPurchaseSpecialPack(profileId);
76
+ }
77
+ async _canPurchaseSpecialPack(profileId, sharedContext) {
78
+ const rows = await sharedContext?.manager?.execute(`SELECT COUNT(*)::INT AS cnt
79
+ FROM netme_special_pack_credits
80
+ WHERE profile_id = ? AND status = 'available'`, [profileId]);
81
+ return (Number(rows?.[0]?.cnt) ?? 0) > 0;
82
+ }
83
+ /**
84
+ * Redime el paquete disponible más antiguo al completarse un pago.
85
+ * Siempre descuenta el más antiguo primero (FIFO por created_at).
86
+ * Retorna el id del pack redimido o null si no había disponibles.
87
+ */
88
+ async redeemOldestPack(customerId, orderId) {
89
+ const profileId = await this.getProfileIdFromCustomer(customerId);
90
+ if (!profileId)
91
+ return null;
92
+ return this._redeemOldestPack(profileId, orderId);
93
+ }
94
+ async _redeemOldestPack(profileId, orderId, sharedContext) {
95
+ // UPDATE con subquery usando ctid para selección atómica del pack más antiguo.
96
+ // FOR UPDATE SKIP LOCKED requiere transacción explícita que no está disponible
97
+ // en este contexto. El ctid es el puntero físico de fila — el UPDATE solo
98
+ // tocará exactamente 1 fila, siendo seguro para llamadas concurrentes poco
99
+ // frecuentes (la redención no es un hot path).
100
+ const rows = await sharedContext?.manager?.execute(`UPDATE netme_special_pack_credits
101
+ SET status = 'redeemed',
102
+ medusa_order_id = ?,
103
+ redeemed_at = NOW(),
104
+ updated_at = NOW()
105
+ WHERE id = (
106
+ SELECT id
107
+ FROM netme_special_pack_credits
108
+ WHERE profile_id = ?
109
+ AND status = 'available'
110
+ ORDER BY created_at ASC
111
+ LIMIT 1
112
+ )
113
+ RETURNING id`, [orderId, profileId]);
114
+ return rows?.[0]?.id ?? null;
115
+ }
116
+ /**
117
+ * Verifica si una lista de variant_ids contiene alguno de la
118
+ * categoría Paquetes a Precio Especial. Usado en el middleware
119
+ * de add-to-cart para saber si aplica la validación de créditos.
120
+ */
121
+ async variantsContainSpecialPack(variantIds) {
122
+ if (!variantIds.length)
123
+ return false;
124
+ return this._variantsContainSpecialPack(variantIds);
125
+ }
126
+ async _variantsContainSpecialPack(variantIds, sharedContext) {
127
+ // Generar placeholders para IN clause
128
+ const placeholders = variantIds.map(() => "?").join(",");
129
+ const rows = await sharedContext?.manager?.execute(`SELECT COUNT(*)::INT AS cnt
130
+ FROM product_variant pv
131
+ JOIN product p ON p.id = pv.product_id
132
+ JOIN product_category_product pcp ON pcp.product_id = p.id
133
+ WHERE pv.id IN (${placeholders})
134
+ AND pcp.product_category_id = ?
135
+ AND pv.deleted_at IS NULL`, [...variantIds, exports.SPECIAL_PACK_CATEGORY_ID]);
136
+ return (Number(rows?.[0]?.cnt) ?? 0) > 0;
137
+ }
138
+ /**
139
+ * Verifica si una orden contiene productos de la categoría
140
+ * Paquetes a Precio Especial.
141
+ */
142
+ async orderContainsSpecialPack(orderId) {
143
+ return this._orderContainsSpecialPack(orderId);
144
+ }
145
+ async _orderContainsSpecialPack(orderId, sharedContext) {
146
+ // Usa DISTINCT ON item_id para evitar doble conteo por versiones de order_item
147
+ const rows = await sharedContext?.manager?.execute(`SELECT COUNT(DISTINCT oli.id)::INT AS cnt
148
+ FROM "order" o
149
+ JOIN order_item oi ON oi.order_id = o.id
150
+ JOIN order_line_item oli ON oli.id = oi.item_id
151
+ JOIN product_variant pv ON pv.id = oli.variant_id
152
+ JOIN product p ON p.id = pv.product_id
153
+ JOIN product_category_product pcp ON pcp.product_id = p.id
154
+ WHERE o.id = ?
155
+ AND pcp.product_category_id = ?
156
+ AND o.deleted_at IS NULL`, [orderId, exports.SPECIAL_PACK_CATEGORY_ID]);
157
+ return (Number(rows?.[0]?.cnt) ?? 0) > 0;
158
+ }
15
159
  }
160
+ __decorate([
161
+ (0, utils_1.InjectManager)(),
162
+ __param(1, (0, utils_1.MedusaContext)()),
163
+ __metadata("design:type", Function),
164
+ __metadata("design:paramtypes", [String, Object]),
165
+ __metadata("design:returntype", Promise)
166
+ ], BundleService.prototype, "_getProfileIdFromCustomer", null);
167
+ __decorate([
168
+ (0, utils_1.InjectManager)(),
169
+ __param(1, (0, utils_1.MedusaContext)()),
170
+ __metadata("design:type", Function),
171
+ __metadata("design:paramtypes", [Number, Object]),
172
+ __metadata("design:returntype", Promise)
173
+ ], BundleService.prototype, "_getAvailableSpecialPacks", null);
174
+ __decorate([
175
+ (0, utils_1.InjectManager)(),
176
+ __param(1, (0, utils_1.MedusaContext)()),
177
+ __metadata("design:type", Function),
178
+ __metadata("design:paramtypes", [Number, Object]),
179
+ __metadata("design:returntype", Promise)
180
+ ], BundleService.prototype, "_canPurchaseSpecialPack", null);
181
+ __decorate([
182
+ (0, utils_1.InjectManager)(),
183
+ __param(2, (0, utils_1.MedusaContext)()),
184
+ __metadata("design:type", Function),
185
+ __metadata("design:paramtypes", [Number, String, Object]),
186
+ __metadata("design:returntype", Promise)
187
+ ], BundleService.prototype, "_redeemOldestPack", null);
188
+ __decorate([
189
+ (0, utils_1.InjectManager)(),
190
+ __param(1, (0, utils_1.MedusaContext)()),
191
+ __metadata("design:type", Function),
192
+ __metadata("design:paramtypes", [Array, Object]),
193
+ __metadata("design:returntype", Promise)
194
+ ], BundleService.prototype, "_variantsContainSpecialPack", null);
195
+ __decorate([
196
+ (0, utils_1.InjectManager)(),
197
+ __param(1, (0, utils_1.MedusaContext)()),
198
+ __metadata("design:type", Function),
199
+ __metadata("design:paramtypes", [String, Object]),
200
+ __metadata("design:returntype", Promise)
201
+ ], BundleService.prototype, "_orderContainsSpecialPack", null);
16
202
  exports.default = BundleService;
17
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2J1bmRsZXMvc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHFEQUF5RDtBQUN6RCw0Q0FBd0M7QUFFeEMsTUFBTSxhQUFjLFNBQVEsSUFBQSxxQkFBYSxFQUFDO0lBQ3RDLE1BQU0sRUFBTixlQUFNO0NBQ1QsQ0FBQztJQUNFLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxTQUFpQjtRQUN6QyxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUM7WUFDbEMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDO1lBQ2YsU0FBUyxFQUFFLENBQUMsZUFBZSxDQUFDO1NBQy9CLENBQUMsQ0FBQTtRQUVGLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQTtJQUM1QixDQUFDO0NBQ0o7QUFFRCxrQkFBZSxhQUFhLENBQUEifQ==
203
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL2J1bmRsZXMvc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSxxREFBdUY7QUFHdkYsNENBQXdDO0FBRXhDLG9EQUFvRDtBQUN2QyxRQUFBLHdCQUF3QixHQUFHLGlDQUFpQyxDQUFBO0FBa0J6RSxNQUFNLGFBQWMsU0FBUSxJQUFBLHFCQUFhLEVBQUM7SUFDeEMsTUFBTSxFQUFOLGVBQU07Q0FDUCxDQUFDO0lBQ0EsS0FBSyxDQUFDLHFCQUFxQixDQUFDLFNBQWlCO1FBQzNDLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQztZQUNwQyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUM7WUFDZixTQUFTLEVBQUUsQ0FBQyxlQUFlLENBQUM7U0FDN0IsQ0FBQyxDQUFBO1FBQ0YsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFBO0lBQzFCLENBQUM7SUFFRCw2REFBNkQ7SUFFN0Q7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLHdCQUF3QixDQUFDLFVBQWtCO1FBQy9DLE9BQU8sSUFBSSxDQUFDLHlCQUF5QixDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ25ELENBQUM7SUFHYSxBQUFOLEtBQUssQ0FBQyx5QkFBeUIsQ0FDckMsVUFBa0IsRUFDRCxhQUFzQztRQUV2RCxNQUFNLElBQUksR0FBRyxNQUFNLGFBQWEsRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUNoRDs7OztlQUlTLEVBQ1QsQ0FBQyxVQUFVLENBQUMsQ0FDb0IsQ0FBQTtRQUNsQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsSUFBSSxJQUFJLENBQUE7SUFDdEMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxVQUFrQjtRQUMvQyxNQUFNLFNBQVMsR0FB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
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * Subscriber: order.payment_captured
4
+ *
5
+ * Cuando se confirma el pago de una orden que contiene un producto
6
+ * de la categoría Paquetes a Precio Especial, redime el pack disponible
7
+ * más antiguo del customer (FIFO por created_at).
8
+ *
9
+ * Solo actúa si la orden contiene al menos un producto de la categoría
10
+ * pcat_01KQDWQ1GCQR1F278TMVWY9WNB.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.config = void 0;
14
+ exports.default = redeemSpecialPackOnPayment;
15
+ const utils_1 = require("@medusajs/framework/utils");
16
+ const bundles_1 = require("../modules/bundles");
17
+ async function redeemSpecialPackOnPayment({ event: { data }, container, }) {
18
+ const orderId = data.id;
19
+ const bundleService = container.resolve(bundles_1.BUNDLE_MODULE);
20
+ const orderModule = container.resolve(utils_1.Modules.ORDER);
21
+ // Verificar si la orden tiene paquetes a precio especial
22
+ const hasSpecialPack = await bundleService.orderContainsSpecialPack(orderId);
23
+ if (!hasSpecialPack)
24
+ return;
25
+ // Obtener el customer de la orden
26
+ const order = await orderModule.retrieveOrder(orderId);
27
+ const customerId = order.customer_id;
28
+ if (!customerId) {
29
+ console.warn(`[special-packs] Orden ${orderId} sin customer_id`);
30
+ return;
31
+ }
32
+ // Redimir el pack más antiguo disponible
33
+ const redeemedPackId = await bundleService.redeemOldestPack(customerId, orderId);
34
+ if (redeemedPackId) {
35
+ console.log(`[special-packs] Pack #${redeemedPackId} redimido para customer ${customerId} en orden ${orderId}`);
36
+ }
37
+ else {
38
+ // El customer compró un paquete especial sin tener disponibles
39
+ // El validador de add-to-cart debería haber prevenido esto
40
+ console.error(`[special-packs] ALERTA: orden ${orderId} con paquete especial pero sin créditos disponibles para customer ${customerId}`);
41
+ }
42
+ }
43
+ exports.config = {
44
+ event: "order.payment_captured",
45
+ };
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkZWVtLXNwZWNpYWwtcGFjay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9yZWRlZW0tc3BlY2lhbC1wYWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7O0dBU0c7OztBQU9ILDZDQW1DQztBQXZDRCxxREFBbUQ7QUFDbkQsZ0RBQWtEO0FBR25DLEtBQUssVUFBVSwwQkFBMEIsQ0FBQyxFQUN2RCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFDZixTQUFTLEdBQ3NCO0lBQy9CLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUE7SUFFdkIsTUFBTSxhQUFhLEdBQWtCLFNBQVMsQ0FBQyxPQUFPLENBQUMsdUJBQWEsQ0FBQyxDQUFBO0lBQ3JFLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBRXBELHlEQUF5RDtJQUN6RCxNQUFNLGNBQWMsR0FBRyxNQUFNLGFBQWEsQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUM1RSxJQUFJLENBQUMsY0FBYztRQUFFLE9BQU07SUFFM0Isa0NBQWtDO0lBQ2xDLE1BQU0sS0FBSyxHQUFHLE1BQU0sV0FBVyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUN0RCxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFBO0lBQ3BDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoQixPQUFPLENBQUMsSUFBSSxDQUFDLHlCQUF5QixPQUFPLGtCQUFrQixDQUFDLENBQUE7UUFDaEUsT0FBTTtJQUNSLENBQUM7SUFFRCx5Q0FBeUM7SUFDekMsTUFBTSxjQUFjLEdBQUcsTUFBTSxhQUFhLENBQUMsZ0JBQWdCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBRWhGLElBQUksY0FBYyxFQUFFLENBQUM7UUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FDVCx5QkFBeUIsY0FBYywyQkFBMkIsVUFBVSxhQUFhLE9BQU8sRUFBRSxDQUNuRyxDQUFBO0lBQ0gsQ0FBQztTQUFNLENBQUM7UUFDTiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBQzNELE9BQU8sQ0FBQyxLQUFLLENBQ1gsaUNBQWlDLE9BQU8scUVBQXFFLFVBQVUsRUFBRSxDQUMxSCxDQUFBO0lBQ0gsQ0FBQztBQUNILENBQUM7QUFFWSxRQUFBLE1BQU0sR0FBcUI7SUFDdEMsS0FBSyxFQUFFLHdCQUF3QjtDQUNoQyxDQUFBIn0=
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * Hook: addToCartWorkflow.validate
4
+ *
5
+ * Se ejecuta antes de agregar cualquier item al carrito (ruta estándar
6
+ * de Medusa o cualquier ruta custom que invoque addToCartWorkflow).
7
+ *
8
+ * Si el item pertenece a la categoría Paquetes a Precio Especial,
9
+ * verifica que el customer tenga al menos 1 crédito disponible.
10
+ * Si no lo tiene, lanza MedusaError.NOT_ALLOWED abortando el workflow.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const utils_1 = require("@medusajs/framework/utils");
14
+ const core_flows_1 = require("@medusajs/medusa/core-flows");
15
+ const bundles_1 = require("../../modules/bundles");
16
+ core_flows_1.addToCartWorkflow.hooks.validate(async ({ input }, { container }) => {
17
+ const variantIds = input.items
18
+ .map((item) => item.variant_id)
19
+ .filter(Boolean);
20
+ if (!variantIds.length)
21
+ return;
22
+ const bundleService = container.resolve(bundles_1.BUNDLE_MODULE);
23
+ // ¿Algún variant es de la categoría Paquetes a Precio Especial?
24
+ const hasSpecialPack = await bundleService.variantsContainSpecialPack(variantIds);
25
+ if (!hasSpecialPack)
26
+ return;
27
+ // Obtener customer del cart (el input solo tiene cart_id)
28
+ const cartModule = container.resolve(utils_1.Modules.CART);
29
+ const cart = await cartModule.retrieveCart(input.cart_id, {
30
+ select: ["id", "customer_id"],
31
+ });
32
+ const customerId = cart.customer_id;
33
+ if (!customerId) {
34
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "Debes iniciar sesión para comprar Paquetes a Precio Especial");
35
+ }
36
+ // Verificar créditos disponibles
37
+ const canPurchase = await bundleService.canPurchaseSpecialPack(customerId);
38
+ if (!canPurchase) {
39
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_ALLOWED, "No tienes Paquetes a Precio Especial disponibles este mes");
40
+ }
41
+ });
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUtc3BlY2lhbC1wYWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9ob29rcy92YWxpZGF0ZS1zcGVjaWFsLXBhY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7R0FTRzs7QUFFSCxxREFBZ0U7QUFDaEUsNERBQStEO0FBQy9ELG1EQUFxRDtBQUdyRCw4QkFBaUIsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUM5QixLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUU7SUFDakMsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLEtBQUs7U0FDM0IsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDO1NBQzlCLE1BQU0sQ0FBQyxPQUFPLENBQWEsQ0FBQTtJQUU5QixJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU07UUFBRSxPQUFNO0lBRTlCLE1BQU0sYUFBYSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsdUJBQWEsQ0FBa0IsQ0FBQTtJQUV2RSxnRUFBZ0U7SUFDaEUsTUFBTSxjQUFjLEdBQUcsTUFBTSxhQUFhLENBQUMsMEJBQTBCLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDakYsSUFBSSxDQUFDLGNBQWM7UUFBRSxPQUFNO0lBRTNCLDBEQUEwRDtJQUMxRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGVBQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUNsRCxNQUFNLElBQUksR0FBRyxNQUFNLFVBQVUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRTtRQUN4RCxNQUFNLEVBQUUsQ0FBQyxJQUFJLEVBQUUsYUFBYSxDQUFDO0tBQzlCLENBQUMsQ0FBQTtJQUVGLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUE7SUFDbkMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2hCLE1BQU0sSUFBSSxtQkFBVyxDQUNuQixtQkFBVyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQzdCLDhEQUE4RCxDQUMvRCxDQUFBO0lBQ0gsQ0FBQztJQUVELGlDQUFpQztJQUNqQyxNQUFNLFdBQVcsR0FBRyxNQUFNLGFBQWEsQ0FBQyxzQkFBc0IsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUMxRSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDakIsTUFBTSxJQUFJLG1CQUFXLENBQ25CLG1CQUFXLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFDN0IsMkRBQTJELENBQzVELENBQUE7SUFDSCxDQUFDO0FBQ0gsQ0FBQyxDQUNGLENBQUEifQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaamx/netme-bundle",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",
@@ -32,19 +32,19 @@
32
32
  ],
33
33
  "scripts": {
34
34
  "build": "medusa plugin:build",
35
- "dev": "medusa plugin:develop",
35
+ "dev": "bash dev.sh",
36
36
  "prepublishOnly": "medusa plugin:build"
37
37
  },
38
38
  "dependencies": {
39
- "@medusajs/js-sdk": "2.13.1"
39
+ "@medusajs/js-sdk": "2.14.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@medusajs/admin-sdk": "2.13.1",
43
- "@medusajs/cli": "2.13.1",
44
- "@medusajs/framework": "2.13.1",
45
- "@medusajs/icons": "2.13.1",
46
- "@medusajs/medusa": "2.13.1",
47
- "@medusajs/test-utils": "2.13.1",
42
+ "@medusajs/admin-sdk": "2.14.2",
43
+ "@medusajs/cli": "2.14.2",
44
+ "@medusajs/framework": "2.14.2",
45
+ "@medusajs/icons": "2.14.2",
46
+ "@medusajs/medusa": "2.14.2",
47
+ "@medusajs/test-utils": "2.14.2",
48
48
  "@medusajs/ui": "4.0.25",
49
49
  "@swc/core": "^1.7.28",
50
50
  "@tanstack/react-query": "^5.0.0",
@@ -61,12 +61,12 @@
61
61
  "yalc": "^1.0.0-pre.53"
62
62
  },
63
63
  "peerDependencies": {
64
- "@medusajs/admin-sdk": "2.13.1",
65
- "@medusajs/cli": "2.13.1",
66
- "@medusajs/framework": "2.13.1",
67
- "@medusajs/icons": "2.13.1",
68
- "@medusajs/medusa": "2.13.1",
69
- "@medusajs/test-utils": "2.13.1",
64
+ "@medusajs/admin-sdk": "2.14.2",
65
+ "@medusajs/cli": "2.14.2",
66
+ "@medusajs/framework": "2.14.2",
67
+ "@medusajs/icons": "2.14.2",
68
+ "@medusajs/medusa": "2.14.2",
69
+ "@medusajs/test-utils": "2.14.2",
70
70
  "@medusajs/ui": "4.0.25",
71
71
  "@tanstack/react-query": "^5.0.0",
72
72
  "react": "^18.3.1",