@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 +12 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +81 -140
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -140
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
}
|
|
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)(
|
|
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
|
-
|
|
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
|
|
8428
|
-
|
|
8429
|
-
|
|
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
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
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 (
|
|
8543
|
-
subscriptionAmount =
|
|
8544
|
-
} else if (
|
|
8545
|
-
subscriptionAmount =
|
|
8546
|
-
} else if (
|
|
8547
|
-
subscriptionAmount =
|
|
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 =
|
|
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
|
-
|
|
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 ?
|
|
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
|
-
{
|
|
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
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
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.
|
|
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;
|