@goweekdays/core 2.11.12 → 2.11.13

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/dist/index.mjs CHANGED
@@ -5435,6 +5435,7 @@ var schemaSubscriptionCompute = Joi20.object({
5435
5435
  seats: Joi20.number().integer().min(1).required(),
5436
5436
  plan: Joi20.string().hex().length(24).required(),
5437
5437
  promoCode: Joi20.string().optional().allow("", null),
5438
+ nextPromoCode: Joi20.string().optional().allow("", null),
5438
5439
  org: Joi20.string().hex().length(24).required()
5439
5440
  });
5440
5441
  var schemaSubscribe = Joi20.object({
@@ -5453,6 +5454,7 @@ var schema2 = {
5453
5454
  };
5454
5455
  var schemaSubscription = Joi20.object({
5455
5456
  ...schema2,
5457
+ billingPeriodStart: Joi20.date().optional().allow("", null),
5456
5458
  org: Joi20.string().hex().length(24).required(),
5457
5459
  orgName: Joi20.string().optional().allow("", null),
5458
5460
  currency: Joi20.string().length(3).required(),
@@ -5499,9 +5501,11 @@ function modelSubscription(data) {
5499
5501
  amount: data.amount,
5500
5502
  currency: data.currency,
5501
5503
  billingCycle: data.billingCycle,
5502
- promoCode: data.promoCode,
5504
+ promoCode: data.promoCode ?? "",
5505
+ nextPromoCode: data.nextPromoCode ?? "",
5503
5506
  status: data.status ?? "active",
5504
5507
  retry: data.retry ?? 0,
5508
+ billingPeriodStart: data.billingPeriodStart,
5505
5509
  nextBillingDate: data.nextBillingDate,
5506
5510
  createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
5507
5511
  updatedAt: data.updatedAt ?? ""
@@ -5822,7 +5826,9 @@ function useSubscriptionRepo() {
5822
5826
  paidSeats: Joi21.number().integer().min(0).optional(),
5823
5827
  amount: Joi21.number().positive().optional().allow(0),
5824
5828
  promoCode: Joi21.string().max(50).optional().allow("", null),
5829
+ nextPromoCode: Joi21.string().max(50).optional().allow("", null),
5825
5830
  status: Joi21.string().valid("active", "due", "overdue", "suspended").optional().allow("", null),
5831
+ billingPeriodStart: Joi21.date().optional().allow("", null),
5826
5832
  nextBillingDate: Joi21.date().optional().allow("", null)
5827
5833
  });
5828
5834
  const { error } = validation.validate(options);
@@ -5958,7 +5964,6 @@ import { BadRequestError as BadRequestError42 } from "@goweekdays/utils";
5958
5964
  import {
5959
5965
  AppError as AppError20,
5960
5966
  BadRequestError as BadRequestError41,
5961
- formatNumber,
5962
5967
  InternalServerError as InternalServerError22,
5963
5968
  logger as logger23,
5964
5969
  useAtlas as useAtlas18
@@ -5993,6 +5998,16 @@ var schemaSubscriptionTransaction = Joi22.object({
5993
5998
  "promo-expired",
5994
5999
  "promo-updated"
5995
6000
  ).required(),
6001
+ metadata: Joi22.object({
6002
+ additionalSeats: Joi22.number().integer().min(1).optional(),
6003
+ seats: Joi22.number().integer().min(0).optional(),
6004
+ paidSeats: Joi22.number().integer().min(0).optional(),
6005
+ plan: Joi22.string().hex().length(24).optional(),
6006
+ promoCode: Joi22.string().optional().allow("", null),
6007
+ nextPromoCode: Joi22.string().optional().allow("", null),
6008
+ billingPeriodStart: Joi22.date().optional().allow("", null),
6009
+ nextBillingDate: Joi22.date().optional().allow("", null)
6010
+ }).optional(),
5996
6011
  description: Joi22.string().optional().allow("", null),
5997
6012
  createdBy: Joi22.string().hex().length(24).required(),
5998
6013
  createdByName: Joi22.string().optional().allow("", null)
@@ -6031,6 +6046,7 @@ function modelSubscriptionTransaction(data) {
6031
6046
  amount: data.amount,
6032
6047
  currency: data.currency,
6033
6048
  type: data.type,
6049
+ metadata: data.metadata ?? {},
6034
6050
  description: data.description ?? "",
6035
6051
  createdBy: data.createdBy,
6036
6052
  createdByName: data.createdByName,
@@ -8583,7 +8599,8 @@ function useSubscriptionService() {
8583
8599
  if (!membership) {
8584
8600
  throw new BadRequestError41("User is not a member of the organization.");
8585
8601
  }
8586
- const nextBillingDate = /* @__PURE__ */ new Date();
8602
+ const billingPeriodStart = /* @__PURE__ */ new Date();
8603
+ const nextBillingDate = new Date(billingPeriodStart);
8587
8604
  nextBillingDate.setDate(nextBillingDate.getDate() + 30);
8588
8605
  const { subscriptionAmount, currency } = await computeFee({
8589
8606
  seats: value.seats,
@@ -8608,6 +8625,7 @@ function useSubscriptionService() {
8608
8625
  amount: subscriptionAmount,
8609
8626
  currency,
8610
8627
  billingCycle: plan.billingCycle,
8628
+ billingPeriodStart,
8611
8629
  nextBillingDate,
8612
8630
  promoCode: value.promoCode
8613
8631
  },
@@ -8711,7 +8729,17 @@ function useSubscriptionService() {
8711
8729
  currency,
8712
8730
  subscription: subscription._id?.toString() ?? "",
8713
8731
  createdBy: value.user,
8714
- createdByName: `${userData.firstName} ${userData.lastName}`
8732
+ createdByName: `${userData.firstName} ${userData.lastName}`,
8733
+ metadata: {
8734
+ additionalSeats,
8735
+ seats: value.seats,
8736
+ paidSeats,
8737
+ plan: value.plan ?? "",
8738
+ promoCode: subscription.promoCode ?? "",
8739
+ nextPromoCode: subscription.nextPromoCode ?? "",
8740
+ billingPeriodStart: subscription.billingPeriodStart,
8741
+ nextBillingDate: subscription.nextBillingDate
8742
+ }
8715
8743
  },
8716
8744
  session
8717
8745
  );
@@ -8776,67 +8804,38 @@ function useSubscriptionService() {
8776
8804
  });
8777
8805
  await updateById(
8778
8806
  subscription._id?.toString() ?? "",
8779
- { promoCode: value.promoCode ?? "", amount: subscriptionAmount },
8807
+ { nextPromoCode: value.promoCode ?? "" },
8780
8808
  session
8781
8809
  );
8782
8810
  if (subscription.promoCode) {
8783
8811
  await updatePromoUsageStatusByOrgId(value.org, "inactive", session);
8784
8812
  }
8785
- let description = `Promo code updated to ${value.promoCode ?? "none"}. At the time of update, ${formatNumber(subscription.paidSeats, {
8786
- decimalPlaces: 0
8787
- })} seat(s) were already included in the subscription.`;
8788
8813
  if (promo && promo._id) {
8789
8814
  await addPromoUsage(
8790
8815
  {
8791
8816
  promo: promo._id,
8792
8817
  org: value.org,
8793
- usedBy: userData.email
8818
+ usedBy: value.user
8794
8819
  },
8795
8820
  session
8796
8821
  );
8797
- const additionalDescription = `${promo.seats ? `Seats beyond ${formatNumber(promo.seats, {
8798
- decimalPlaces: 0
8799
- })} are charged at the standard rate.` : ""}`;
8800
- if (promo.type === "flat") {
8801
- description += ` ${formatNumber(promo.flatRate ?? 0, {
8802
- currency,
8803
- useSymbol: true
8804
- })} ${promo.seats ? `limited to ${formatNumber(promo.seats, {
8805
- decimalPlaces: 0
8806
- })} seat(s)` : " for all seats"}. ${additionalDescription}`;
8807
- }
8808
- if (promo.type === "fixed") {
8809
- description += ` ${formatNumber(promo.fixedRate ?? 0, {
8810
- currency,
8811
- useSymbol: true
8812
- })} per seat${promo.seats ? `, limited to ${formatNumber(promo.seats, {
8813
- decimalPlaces: 0
8814
- })} seat(s)` : ""}. ${additionalDescription}`;
8815
- }
8816
- if (promo.type === "volume") {
8817
- if (promo.tiers && promo.tiers.length > 0) {
8818
- const tierDescriptions = promo.tiers.map((tier) => {
8819
- const maxSeatsDesc = tier.maxSeats === 0 ? "and above" : `to ${formatNumber(tier.maxSeats, { decimalPlaces: 0 })}`;
8820
- return `${formatNumber(tier.minSeats, {
8821
- decimalPlaces: 0
8822
- })} ${maxSeatsDesc} ${formatNumber(tier.rate, {
8823
- currency,
8824
- useSymbol: true
8825
- })} per seat`;
8826
- }).join(", ");
8827
- description += ` Volume tiers, ${tierDescriptions}.`;
8828
- }
8829
- }
8830
8822
  }
8831
8823
  await addTransaction(
8832
8824
  {
8833
8825
  type: "promo-updated",
8834
- description,
8826
+ description: `Promo code ${value.promoCode || "removed"} scheduled to take effect on the next billing cycle.`,
8835
8827
  amount: 0,
8836
- currency,
8828
+ currency: subscription.currency,
8837
8829
  subscription: subscription._id?.toString() ?? "",
8838
8830
  createdBy: value.user,
8839
- createdByName: `${userData.firstName} ${userData.lastName}`
8831
+ metadata: {
8832
+ seats: subscription.seats,
8833
+ paidSeats: subscription.paidSeats,
8834
+ promoCode: subscription.promoCode,
8835
+ nextPromoCode: value.promoCode ?? "",
8836
+ billingPeriodStart: subscription.billingPeriodStart,
8837
+ nextBillingDate: subscription.nextBillingDate
8838
+ }
8840
8839
  },
8841
8840
  session
8842
8841
  );
@@ -8996,39 +8995,43 @@ function useSubscriptionService() {
8996
8995
  }
8997
8996
  const ledgerBill = await getByInvoice(invoiceId);
8998
8997
  if (!ledgerBill) {
8999
- throw new BadRequestError41(
9000
- "Ledger bill not found for the given invoice ID."
9001
- );
8998
+ throw new BadRequestError41("Ledger bill not found.");
9002
8999
  }
9003
9000
  const orgId = String(ledgerBill.org);
9004
- const org = await getOrgById(orgId);
9005
- if (!org) {
9006
- throw new BadRequestError41("Organization not found for the ledger bill.");
9007
- }
9008
9001
  const subscription = await getByOrg(orgId);
9009
9002
  if (!subscription) {
9010
- throw new BadRequestError41("Subscription not found for the organization.");
9003
+ throw new BadRequestError41("Subscription not found.");
9011
9004
  }
9012
9005
  const plan = await getDefaultPlan();
9013
9006
  if (!plan) {
9014
- throw new BadRequestError41("Default plan not found.");
9007
+ throw new BadRequestError41("Plan not found.");
9015
9008
  }
9016
9009
  const session = useAtlas18.getClient()?.startSession();
9017
9010
  if (!session) {
9018
- throw new Error("Unable to start database session.");
9011
+ throw new InternalServerError22("Unable to start database session.");
9019
9012
  }
9020
9013
  try {
9021
9014
  session.startTransaction();
9022
- const subscriptionId = String(subscription._id);
9023
- const nextBillingDate = /* @__PURE__ */ new Date();
9015
+ const billingPeriodStart = /* @__PURE__ */ new Date();
9016
+ const nextBillingDate = new Date(billingPeriodStart);
9024
9017
  nextBillingDate.setMonth(nextBillingDate.getMonth() + 1);
9018
+ const effectivePromoCode = subscription.nextPromoCode || subscription.promoCode;
9019
+ const promo = effectivePromoCode ? await getPromoByCode(effectivePromoCode) : null;
9020
+ const monthlyAmount = computeMonthlyAmount(
9021
+ subscription.seats,
9022
+ plan.price,
9023
+ promo
9024
+ );
9025
9025
  await updateById(
9026
- subscriptionId,
9026
+ subscription._id?.toString() ?? "",
9027
9027
  {
9028
9028
  status: "active",
9029
+ billingPeriodStart,
9029
9030
  nextBillingDate,
9030
9031
  paidSeats: subscription.seats,
9031
- amount: plan.price * subscription.seats
9032
+ amount: Math.round(monthlyAmount * 100) / 100,
9033
+ promoCode: effectivePromoCode,
9034
+ nextPromoCode: ""
9032
9035
  },
9033
9036
  session
9034
9037
  );
@@ -9039,14 +9042,7 @@ function useSubscriptionService() {
9039
9042
  return "Successfully processed paid invoice.";
9040
9043
  } catch (error2) {
9041
9044
  await session.abortTransaction();
9042
- logger23.log({
9043
- level: "error",
9044
- message: `Failed to process paid invoice ${invoiceId}: ${error2 instanceof Error ? error2.message : String(error2)}`
9045
- });
9046
- if (error2 instanceof AppError20) {
9047
- throw error2;
9048
- }
9049
- throw new InternalServerError22("Failed to process paid invoice.");
9045
+ throw error2;
9050
9046
  } finally {
9051
9047
  session.endSession();
9052
9048
  }
@@ -9586,6 +9582,7 @@ function useOrgService() {
9586
9582
  paidSeats: value.seats,
9587
9583
  currency: plan.currency,
9588
9584
  billingCycle: plan.billingCycle,
9585
+ billingPeriodStart: currentDate,
9589
9586
  nextBillingDate
9590
9587
  },
9591
9588
  session