dev #23

Merged
Seazn merged 16 commits from dev into main 2026-05-21 17:34:48 +00:00
Showing only changes of commit df1cf07390 - Show all commits

View File

@ -7,6 +7,22 @@ const ReferralService = require('../referral/ReferralService');
const ReferralTokenRepository = require('../../repositories/referral/ReferralTokenRepository'); const ReferralTokenRepository = require('../../repositories/referral/ReferralTokenRepository');
const MailService = require('../email/MailService'); const MailService = require('../email/MailService');
const CAPSULES_PER_PACK = 10;
const MIN_ABO_PACKS = 6;
const MAX_ABO_PACKS = 10000;
function getPackCountError(totalPacks) {
if (totalPacks < MIN_ABO_PACKS) {
return `Order must contain at least ${MIN_ABO_PACKS} packs (${MIN_ABO_PACKS * CAPSULES_PER_PACK} capsules).`;
}
if (totalPacks > MAX_ABO_PACKS) {
return `Order cannot contain more than ${MAX_ABO_PACKS} packs (${MAX_ABO_PACKS * CAPSULES_PER_PACK} capsules).`;
}
return null;
}
class AbonemmentService { class AbonemmentService {
constructor() { constructor() {
this.repo = new AbonemmentRepository(); this.repo = new AbonemmentRepository();
@ -40,7 +56,7 @@ class AbonemmentService {
return typeof email === 'string' ? email.trim().toLowerCase() : null; return typeof email === 'string' ? email.trim().toLowerCase() : null;
} }
// NEW: single bundle subscribe using items array (12 packs, 120 capsules) // NEW: single bundle subscribe using items array (pack-based order content)
async subscribeOrder({ async subscribeOrder({
items, items,
billingInterval, billingInterval,
@ -114,7 +130,7 @@ class AbonemmentService {
const coffeeId = item?.coffeeId; const coffeeId = item?.coffeeId;
const packs = Number(item?.quantity ?? 0); const packs = Number(item?.quantity ?? 0);
if (!coffeeId) throw new Error('coffeeId is required for each item'); if (!coffeeId) throw new Error('coffeeId is required for each item');
if (!Number.isFinite(packs) || packs <= 0) throw new Error('quantity must be a positive integer per item'); if (!Number.isInteger(packs) || packs <= 0) throw new Error('quantity must be a positive integer per item');
const product = await this.getCoffeeProduct(coffeeId); const product = await this.getCoffeeProduct(coffeeId);
if (!product || !product.is_active) throw new Error(`Product ${coffeeId} not available`); if (!product || !product.is_active) throw new Error(`Product ${coffeeId} not available`);
@ -134,6 +150,9 @@ class AbonemmentService {
}); });
} }
const packCountError = getPackCountError(totalPacks);
if (packCountError) throw new Error(packCountError);
const now = new Date(); const now = new Date();
const nextBilling = this.addInterval(now, billingInterval || 'month', intervalCount || 1); const nextBilling = this.addInterval(now, billingInterval || 'month', intervalCount || 1);
@ -590,7 +609,7 @@ class AbonemmentService {
const coffeeId = item?.coffeeId; const coffeeId = item?.coffeeId;
const packs = Number(item?.quantity ?? 0); const packs = Number(item?.quantity ?? 0);
if (!coffeeId) throw new Error('coffeeId is required for each item'); if (!coffeeId) throw new Error('coffeeId is required for each item');
if (!Number.isFinite(packs) || packs <= 0) { if (!Number.isInteger(packs) || packs <= 0) {
throw new Error('quantity must be a positive integer per item'); throw new Error('quantity must be a positive integer per item');
} }
@ -611,9 +630,8 @@ class AbonemmentService {
}); });
} }
if (totalPacks !== 6 && totalPacks !== 12) { const packCountError = getPackCountError(totalPacks);
throw new Error('Order must contain exactly 6 packs (60 capsules) or 12 packs (120 capsules).'); if (packCountError) throw new Error(packCountError);
}
const previousPacks = Array.isArray(abon.pack_breakdown) const previousPacks = Array.isArray(abon.pack_breakdown)
? abon.pack_breakdown.reduce((sum, item) => sum + Number(item?.packs || item?.quantity || 0), 0) ? abon.pack_breakdown.reduce((sum, item) => sum + Number(item?.packs || item?.quantity || 0), 0)