@goweekdays/core 2.11.9 → 2.11.11

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @goweekdays/core
2
2
 
3
+ ## 2.11.11
4
+
5
+ ### Patch Changes
6
+
7
+ - ae3339b: Refactor and simplify subscription fee computation logic
8
+
9
+ ## 2.11.10
10
+
11
+ ### Patch Changes
12
+
13
+ - 4c31cef: Update logout to use cookie and clear user sessions
14
+
3
15
  ## 2.11.9
4
16
 
5
17
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -930,7 +930,7 @@ declare function useSubscriptionService(): {
930
930
  promoCode?: string;
931
931
  org: string;
932
932
  plan: string;
933
- }, skipProration?: boolean) => Promise<{
933
+ }) => Promise<{
934
934
  monthlyAmount: number;
935
935
  proratedAmount: number;
936
936
  subscriptionAmount: number;
package/dist/index.js CHANGED
@@ -633,7 +633,10 @@ function useAuthService() {
633
633
  if (!isPasswordValid) {
634
634
  throw new import_utils2.BadRequestError("Invalid password");
635
635
  }
636
- const { setCache } = (0, import_utils2.useCache)(`user:${_user._id?.toString()}`);
636
+ const { setCache, delNamespace } = (0, import_utils2.useCache)(
637
+ `user:${_user._id?.toString()}`
638
+ );
639
+ await delNamespace();
637
640
  const sid = v4_default();
638
641
  const cacheKey = `sid:${sid}`;
639
642
  await setCache(cacheKey, _user, 14400);
@@ -8414,147 +8417,85 @@ function useSubscriptionService() {
8414
8417
  }
8415
8418
  return total;
8416
8419
  }
8417
- async function computeFee(value, skipProration) {
8420
+ function computeMonthlyAmount(seats, planPrice, promo) {
8421
+ if (!promo)
8422
+ return planPrice * seats;
8423
+ const limit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
8424
+ switch (promo.type) {
8425
+ case "fixed":
8426
+ return Math.min(seats, limit) * (promo.fixedRate ?? 0) + Math.max(seats - limit, 0) * planPrice;
8427
+ case "flat":
8428
+ return (promo.flatRate ?? 0) + Math.max(seats - limit, 0) * planPrice;
8429
+ case "volume":
8430
+ return promo.tiers?.length ? calculateVolumeTierAmount(promo.tiers, 1, seats, planPrice) : planPrice * seats;
8431
+ default:
8432
+ return planPrice * seats;
8433
+ }
8434
+ }
8435
+ function computeProration(subscription, seats, plan, promo) {
8436
+ const additionalSeats = Math.max(0, seats - subscription.paidSeats);
8437
+ if (additionalSeats === 0)
8438
+ return 0;
8439
+ const today = /* @__PURE__ */ new Date();
8440
+ const nextBilling = new Date(subscription.nextBillingDate);
8441
+ const daysRemaining = Math.max(
8442
+ 0,
8443
+ (nextBilling.getTime() - today.getTime()) / 864e5
8444
+ );
8445
+ const cycleDays = plan.billingCycle === "yearly" ? 365 : 30;
8446
+ if (daysRemaining === 0)
8447
+ return 0;
8448
+ const additionalAmount = computeMonthlyAmount(
8449
+ additionalSeats,
8450
+ plan.price,
8451
+ promo
8452
+ );
8453
+ return additionalAmount / cycleDays * daysRemaining;
8454
+ }
8455
+ async function computeFee(value) {
8418
8456
  const { error } = schemaSubscriptionCompute.validate(value);
8419
8457
  if (error) {
8420
8458
  throw new import_utils44.BadRequestError(`Invalid subscription data: ${error.message}`);
8421
8459
  }
8422
8460
  const existingSubscription = await getByOrg(value.org);
8423
8461
  const plan = await getPlanById(value.plan);
8424
- if (!plan) {
8462
+ if (!plan)
8425
8463
  throw new import_utils44.BadRequestError("Plan not found.");
8464
+ const isNew = !existingSubscription;
8465
+ const isPromoChange = !!existingSubscription && value.promoCode !== void 0 && value.promoCode !== existingSubscription.promoCode;
8466
+ const isSeatIncrease = !!existingSubscription && value.seats > existingSubscription.seats;
8467
+ const isSeatDecrease = !!existingSubscription && value.seats < existingSubscription.seats;
8468
+ if (isPromoChange && isSeatIncrease) {
8469
+ throw new import_utils44.BadRequestError(
8470
+ "Cannot change promo code while increasing seats. Perform actions separately."
8471
+ );
8426
8472
  }
8427
- const org = await getOrgById(value.org);
8428
- if (!org) {
8429
- throw new import_utils44.BadRequestError("Organization not found.");
8430
- }
8431
- let promo = null;
8432
- const promoCode = value.promoCode;
8433
- if (promoCode) {
8434
- promo = await getPromoByCode(promoCode);
8435
- if (!promo) {
8436
- throw new import_utils44.BadRequestError("Promo code not found.");
8437
- }
8438
- if (promo.usage && promo.usage > 0) {
8439
- const currentUsageCount = await countByPromoId(
8440
- promo._id?.toString() ?? ""
8441
- );
8442
- const isAlreadyUsingPromo = existingSubscription?.promoCode === promoCode;
8443
- if (!isAlreadyUsingPromo && currentUsageCount >= promo.usage) {
8444
- throw new import_utils44.BadRequestError(
8445
- "Promo code has reached its maximum usage limit."
8446
- );
8447
- }
8448
- }
8449
- }
8450
- let monthlyAmount = plan.price * value.seats;
8451
- if (promo) {
8452
- const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
8453
- switch (promo.type) {
8454
- case "fixed": {
8455
- const promoSeats = Math.min(value.seats, promoSeatLimit);
8456
- const standardSeats = Math.max(value.seats - promoSeatLimit, 0);
8457
- monthlyAmount = Math.max(promo.fixedRate ?? 0, 0) * promoSeats + plan.price * standardSeats;
8458
- break;
8459
- }
8460
- case "flat": {
8461
- const standardSeats = Math.max(value.seats - promoSeatLimit, 0);
8462
- monthlyAmount = (promo.flatRate ?? 0) + plan.price * standardSeats;
8463
- break;
8464
- }
8465
- case "volume": {
8466
- if (promo.tiers && promo.tiers.length > 0) {
8467
- monthlyAmount = calculateVolumeTierAmount(
8468
- promo.tiers,
8469
- 1,
8470
- value.seats,
8471
- plan.price
8472
- );
8473
- }
8474
- break;
8475
- }
8476
- default:
8477
- monthlyAmount = plan.price * value.seats;
8478
- }
8479
- }
8473
+ const effectivePromoCode = isPromoChange ? value.promoCode : existingSubscription?.promoCode;
8474
+ const promo = effectivePromoCode ? await getPromoByCode(effectivePromoCode) : null;
8475
+ const monthlyAmount = computeMonthlyAmount(value.seats, plan.price, promo);
8480
8476
  let proratedAmount = 0;
8481
- let daysRemaining = 0;
8482
- let totalDaysInCycle = 30;
8483
- if (existingSubscription) {
8484
- const today = /* @__PURE__ */ new Date();
8485
- const nextBillingDate = new Date(existingSubscription.nextBillingDate);
8486
- const timeDiff = nextBillingDate.getTime() - today.getTime();
8487
- daysRemaining = Math.max(0, Math.ceil(timeDiff / (1e3 * 60 * 60 * 24)));
8488
- if (plan.billingCycle === "yearly") {
8489
- totalDaysInCycle = 365;
8490
- }
8491
- daysRemaining = Math.min(daysRemaining, totalDaysInCycle);
8492
- const daysElapsed = totalDaysInCycle - daysRemaining;
8493
- const additionalSeats = Math.max(
8494
- 0,
8495
- value.seats - existingSubscription.paidSeats
8477
+ if (existingSubscription && isSeatIncrease && !isPromoChange) {
8478
+ proratedAmount = computeProration(
8479
+ existingSubscription,
8480
+ value.seats,
8481
+ plan,
8482
+ promo
8496
8483
  );
8497
- if (additionalSeats > 0 && daysRemaining > 0 && daysElapsed > 0 && !skipProration) {
8498
- let additionalSeatsAmount = 0;
8499
- if (promo?.type === "volume" && promo.tiers && promo.tiers.length > 0) {
8500
- additionalSeatsAmount = calculateVolumeTierAmount(
8501
- promo.tiers,
8502
- existingSubscription.paidSeats + 1,
8503
- additionalSeats,
8504
- plan.price
8505
- );
8506
- } else if (promo?.type === "fixed") {
8507
- const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
8508
- const startSeat = existingSubscription.paidSeats + 1;
8509
- const endSeat = value.seats;
8510
- const promoSeatsInRange = Math.max(
8511
- 0,
8512
- Math.min(promoSeatLimit, endSeat) - startSeat + 1
8513
- );
8514
- const standardSeatsInRange = Math.max(
8515
- 0,
8516
- additionalSeats - promoSeatsInRange
8517
- );
8518
- additionalSeatsAmount = (promo.fixedRate ?? 0) * promoSeatsInRange + plan.price * standardSeatsInRange;
8519
- } else if (promo?.type === "flat") {
8520
- const promoSeatLimit = promo.seats && promo.seats > 0 ? promo.seats : Infinity;
8521
- const startSeat = existingSubscription.paidSeats + 1;
8522
- const endSeat = value.seats;
8523
- if (startSeat > promoSeatLimit) {
8524
- additionalSeatsAmount = plan.price * additionalSeats;
8525
- } else {
8526
- const seatsStillCoveredByFlat = Math.max(
8527
- 0,
8528
- Math.min(promoSeatLimit, endSeat) - startSeat + 1
8529
- );
8530
- const seatsAtPlanPrice = additionalSeats - seatsStillCoveredByFlat;
8531
- additionalSeatsAmount = plan.price * seatsAtPlanPrice;
8532
- }
8533
- } else {
8534
- additionalSeatsAmount = plan.price * additionalSeats;
8535
- }
8536
- const dailyRate = additionalSeatsAmount / totalDaysInCycle;
8537
- proratedAmount = dailyRate * daysRemaining;
8538
- }
8539
8484
  }
8540
- const isIncrease = existingSubscription && value.seats > existingSubscription.paidSeats;
8541
8485
  let subscriptionAmount;
8542
- if (!existingSubscription) {
8543
- subscriptionAmount = Math.round(monthlyAmount * 100) / 100;
8544
- } else if (proratedAmount > 0) {
8545
- subscriptionAmount = Math.round((existingSubscription.amount + proratedAmount) * 100) / 100;
8546
- } else if (isIncrease) {
8547
- subscriptionAmount = Math.round(monthlyAmount * 100) / 100;
8486
+ if (isNew) {
8487
+ subscriptionAmount = monthlyAmount;
8488
+ } else if (isPromoChange) {
8489
+ subscriptionAmount = monthlyAmount;
8490
+ } else if (isSeatIncrease) {
8491
+ subscriptionAmount = existingSubscription.amount + proratedAmount;
8548
8492
  } else {
8549
- subscriptionAmount = Math.round(existingSubscription.amount * 100) / 100;
8493
+ subscriptionAmount = existingSubscription.amount;
8550
8494
  }
8551
8495
  return {
8552
- // The monthly fee for the next billing cycle
8553
8496
  monthlyAmount: Math.round(monthlyAmount * 100) / 100,
8554
- // The prorated amount to charge now for mid-cycle seat additions
8555
8497
  proratedAmount: Math.round(proratedAmount * 100) / 100,
8556
- // The new subscription.amount for updates
8557
- subscriptionAmount,
8498
+ subscriptionAmount: Math.round(subscriptionAmount * 100) / 100,
8558
8499
  currency: plan.currency
8559
8500
  };
8560
8501
  }
@@ -8696,20 +8637,23 @@ function useSubscriptionService() {
8696
8637
  const { subscriptionAmount, proratedAmount, currency } = await computeFee(
8697
8638
  {
8698
8639
  seats: value.seats,
8699
- promoCode: value.promoCode ?? "",
8700
8640
  plan: value.plan ?? "",
8701
8641
  org: value.org
8702
8642
  }
8703
8643
  );
8704
8644
  const seatIncreased = value.seats > subscription.paidSeats;
8705
- const additionalSeats = value.seats - subscription.paidSeats;
8706
- const paidSeats = seatIncreased ? value.seats : subscription.paidSeats;
8645
+ const additionalSeats = seatIncreased ? value.seats - subscription.paidSeats : 0;
8646
+ const paidSeats = seatIncreased ? subscription.paidSeats + additionalSeats : subscription.paidSeats;
8707
8647
  await updateById(
8708
8648
  subscription._id?.toString() ?? "",
8709
- { seats: value.seats, amount: subscriptionAmount, paidSeats },
8649
+ {
8650
+ seats: value.seats,
8651
+ amount: subscriptionAmount,
8652
+ paidSeats
8653
+ },
8710
8654
  session
8711
8655
  );
8712
- if (seatIncreased) {
8656
+ if (seatIncreased && proratedAmount > 0) {
8713
8657
  await addTransaction(
8714
8658
  {
8715
8659
  type: "add-seat",
@@ -8775,15 +8719,12 @@ function useSubscriptionService() {
8775
8719
  if (!plan) {
8776
8720
  throw new import_utils44.BadRequestError("Plan not found.");
8777
8721
  }
8778
- const { subscriptionAmount, currency } = await computeFee(
8779
- {
8780
- seats: subscription.seats,
8781
- promoCode: value.promoCode ?? "",
8782
- plan: plan._id?.toString() ?? "",
8783
- org: value.org
8784
- },
8785
- true
8786
- );
8722
+ const { subscriptionAmount, currency } = await computeFee({
8723
+ seats: subscription.seats,
8724
+ promoCode: value.promoCode ?? "",
8725
+ plan: plan._id?.toString() ?? "",
8726
+ org: value.org
8727
+ });
8787
8728
  await updateById(
8788
8729
  subscription._id?.toString() ?? "",
8789
8730
  { promoCode: value.promoCode ?? "", amount: subscriptionAmount },
@@ -11173,7 +11114,7 @@ function useAuthController() {
11173
11114
  }
11174
11115
  }
11175
11116
  async function logout(req, res, next) {
11176
- const user = req.headers["user"] ?? "";
11117
+ const user = req.cookies.user;
11177
11118
  if (!user) {
11178
11119
  next(new import_utils54.BadRequestError("Failed to identify user from request."));
11179
11120
  return;