@goweekdays/core 0.0.11 → 0.0.12

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
@@ -12389,10 +12389,10 @@ import { BadRequestError as BadRequestError7 } from "@goweekdays/utils";
12389
12389
  import Joi2 from "joi";
12390
12390
  import { ObjectId as ObjectId8 } from "mongodb";
12391
12391
  function MMember(value) {
12392
- const schema = Joi2.object({
12392
+ const schema3 = Joi2.object({
12393
12393
  _id: Joi2.string().hex().optional().allow("", null),
12394
- org: Joi2.string().hex().required(),
12395
- orgName: Joi2.string().required(),
12394
+ org: Joi2.string().hex().optional().allow("", null),
12395
+ orgName: Joi2.string().optional().allow("", null),
12396
12396
  name: Joi2.string().required(),
12397
12397
  user: Joi2.string().hex().required(),
12398
12398
  role: Joi2.string().hex().required(),
@@ -12401,7 +12401,7 @@ function MMember(value) {
12401
12401
  updatedAt: Joi2.string().optional().allow("", null),
12402
12402
  deletedAt: Joi2.string().optional().allow("", null)
12403
12403
  });
12404
- const { error } = schema.validate(value);
12404
+ const { error } = schema3.validate(value);
12405
12405
  if (error) {
12406
12406
  throw new BadRequestError7(error.message);
12407
12407
  }
@@ -12428,8 +12428,8 @@ function MMember(value) {
12428
12428
  }
12429
12429
  return {
12430
12430
  _id: value._id,
12431
- org: value.org,
12432
- orgName: value.orgName,
12431
+ org: value.org ?? "",
12432
+ orgName: value.orgName ?? "",
12433
12433
  name: value.name,
12434
12434
  user: value.user,
12435
12435
  role: value.role,
@@ -13492,7 +13492,10 @@ function useRoleRepo() {
13492
13492
  }
13493
13493
  async function createUniqueIndex() {
13494
13494
  try {
13495
- await collection.createIndex({ name: 1, type: 1 }, { unique: true });
13495
+ await collection.createIndex(
13496
+ { name: 1, type: 1, org: 1 },
13497
+ { unique: true }
13498
+ );
13496
13499
  } catch (error) {
13497
13500
  throw new InternalServerError12("Failed to create unique index on role.");
13498
13501
  }
@@ -13506,7 +13509,7 @@ function useRoleRepo() {
13506
13509
  logger4.log({ level: "error", message: `${error}` });
13507
13510
  const isDuplicated = error.message.includes("duplicate");
13508
13511
  if (isDuplicated) {
13509
- throw new BadRequestError13("Item role already exists");
13512
+ throw new BadRequestError13("Role already exists");
13510
13513
  }
13511
13514
  throw new InternalServerError12("Failed to create role.");
13512
13515
  }
@@ -15526,36 +15529,75 @@ function useCommentController() {
15526
15529
 
15527
15530
  // src/models/subscription.model.ts
15528
15531
  import { BadRequestError as BadRequestError22 } from "@goweekdays/utils";
15532
+ import Joi11 from "joi";
15529
15533
  import { ObjectId as ObjectId20 } from "mongodb";
15530
15534
  function MSubscription(value) {
15531
- if (value._id) {
15532
- try {
15533
- value._id = new ObjectId20(value._id);
15534
- } catch (error) {
15535
- throw new BadRequestError22("Invalid ID.");
15536
- }
15537
- }
15538
- if (value.user) {
15539
- try {
15540
- value.user = new ObjectId20(value.user);
15541
- } catch (error) {
15542
- throw new BadRequestError22("Invalid user ID.");
15543
- }
15544
- }
15545
- if (value.org) {
15546
- try {
15547
- value.org = new ObjectId20(value.org);
15548
- } catch (error) {
15549
- throw new BadRequestError22("Invalid org ID.");
15535
+ const schema3 = Joi11.object({
15536
+ _id: Joi11.string().hex().optional().allow("", null),
15537
+ user: Joi11.string().hex().optional().allow("", null),
15538
+ org: Joi11.string().hex().optional().allow("", null),
15539
+ customerId: Joi11.string().required(),
15540
+ paymentMethodId: Joi11.string().required(),
15541
+ amount: Joi11.number().positive().min(0).required(),
15542
+ currency: Joi11.string().required(),
15543
+ description: Joi11.string().optional().allow("", null),
15544
+ promoCode: Joi11.string().optional().allow("", null),
15545
+ type: Joi11.string().valid("organization", "affiliate").required(),
15546
+ seats: Joi11.number().optional().min(0).allow(null, ""),
15547
+ status: Joi11.string().optional().allow("", null),
15548
+ billingCycle: Joi11.string().valid("monthly", "yearly").required(),
15549
+ // Ensure valid values
15550
+ nextBillingDate: Joi11.date().optional(),
15551
+ lastPaymentStatus: Joi11.string().optional().allow("", null),
15552
+ failedAttempts: Joi11.number().optional().allow("", null),
15553
+ createdAt: Joi11.date().optional(),
15554
+ updatedAt: Joi11.string().optional().allow("", null),
15555
+ deletedAt: Joi11.string().optional().allow("", null)
15556
+ }).custom((value2, helpers) => {
15557
+ if (!value2.user && !value2.org) {
15558
+ return helpers.error("any.invalid", {
15559
+ message: "Either user or org is required."
15560
+ });
15550
15561
  }
15551
- }
15562
+ return value2;
15563
+ });
15564
+ const { error } = schema3.validate(value);
15565
+ if (error) {
15566
+ throw new BadRequestError22(error.details[0].message);
15567
+ }
15568
+ if (value._id)
15569
+ value._id = new ObjectId20(value._id);
15570
+ if (value.user)
15571
+ value.user = new ObjectId20(value.user);
15572
+ if (value.org)
15573
+ value.org = new ObjectId20(value.org);
15574
+ const createdAt = value.createdAt ? new Date(value.createdAt) : /* @__PURE__ */ new Date();
15575
+ const nextBillingDate = new Date(createdAt);
15576
+ if (value.billingCycle === "monthly") {
15577
+ nextBillingDate.setMonth(nextBillingDate.getMonth() + 1);
15578
+ } else if (value.billingCycle === "yearly") {
15579
+ nextBillingDate.setFullYear(nextBillingDate.getFullYear() + 1);
15580
+ }
15581
+ nextBillingDate.setDate(nextBillingDate.getDate() + 1);
15552
15582
  return {
15553
15583
  _id: value._id,
15554
15584
  user: value.user ?? "",
15555
15585
  org: value.org ?? "",
15556
- subscriptionId: value.subscriptionId,
15586
+ customerId: value.customerId,
15587
+ paymentMethodId: value.paymentMethodId,
15588
+ amount: value.amount,
15589
+ currency: value.currency,
15590
+ description: value.description ?? "",
15591
+ type: value.type,
15592
+ promoCode: value.promoCode ?? "",
15593
+ seats: value.seats ?? 0,
15557
15594
  status: "active",
15558
- createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
15595
+ billingCycle: value.billingCycle,
15596
+ nextBillingDate: nextBillingDate.toISOString(),
15597
+ // Fixed nextBillingDate logic
15598
+ lastPaymentStatus: value.lastPaymentStatus ?? "success",
15599
+ failedAttempts: value.failedAttempts ?? 0,
15600
+ createdAt: createdAt.toISOString(),
15559
15601
  updatedAt: value.updatedAt ?? "",
15560
15602
  deletedAt: value.deletedAt ?? ""
15561
15603
  };
@@ -15564,6 +15606,7 @@ function MSubscription(value) {
15564
15606
  // src/repositories/subscription.repository.ts
15565
15607
  import { BadRequestError as BadRequestError23, logger as logger10, paginate as paginate9, useAtlas as useAtlas15 } from "@goweekdays/utils";
15566
15608
  import { ObjectId as ObjectId21 } from "mongodb";
15609
+ import Joi12 from "joi";
15567
15610
  function useSubscriptionRepo() {
15568
15611
  const db = useAtlas15.getDb();
15569
15612
  if (!db) {
@@ -15583,7 +15626,10 @@ function useSubscriptionRepo() {
15583
15626
  }
15584
15627
  async function createUniqueIndex() {
15585
15628
  try {
15586
- await collection.createIndex({ user: 1, status: 1 }, { unique: true });
15629
+ await collection.createIndex(
15630
+ { user: 1, org: 1, status: 1 },
15631
+ { unique: true }
15632
+ );
15587
15633
  } catch (error) {
15588
15634
  throw new BadRequestError23(
15589
15635
  "Failed to create unique index on subscription."
@@ -15596,6 +15642,7 @@ function useSubscriptionRepo() {
15596
15642
  const res = await collection.insertOne(value, { session });
15597
15643
  return res.insertedId;
15598
15644
  } catch (error) {
15645
+ console.log(error);
15599
15646
  throw new BadRequestError23("Failed to create subscription.");
15600
15647
  }
15601
15648
  }
@@ -15623,6 +15670,36 @@ function useSubscriptionRepo() {
15623
15670
  throw new BadRequestError23("Failed to get subscription by ID.");
15624
15671
  }
15625
15672
  }
15673
+ async function getByAffiliateUserId(user) {
15674
+ try {
15675
+ user = new ObjectId21(user);
15676
+ } catch (error) {
15677
+ throw new BadRequestError23("Invalid user ID.");
15678
+ }
15679
+ try {
15680
+ return await collection.findOne({
15681
+ user,
15682
+ type: "affiliate"
15683
+ });
15684
+ } catch (error) {
15685
+ throw new BadRequestError23("Failed to get subscription by ID.");
15686
+ }
15687
+ }
15688
+ async function getByOrgId(org) {
15689
+ try {
15690
+ org = new ObjectId21(org);
15691
+ } catch (error) {
15692
+ throw new BadRequestError23("Invalid org ID.");
15693
+ }
15694
+ try {
15695
+ return await collection.findOne({
15696
+ org,
15697
+ type: "organization"
15698
+ });
15699
+ } catch (error) {
15700
+ throw new BadRequestError23("Failed to get subscription by ID.");
15701
+ }
15702
+ }
15626
15703
  async function getBySubscriptionId(subscriptionId) {
15627
15704
  try {
15628
15705
  return await collection.findOne({ subscriptionId });
@@ -15672,6 +15749,112 @@ function useSubscriptionRepo() {
15672
15749
  throw new BadRequestError23("Failed to update subscription status.");
15673
15750
  }
15674
15751
  }
15752
+ async function getDueSubscriptions(BATCH_SIZE = 100) {
15753
+ const today = /* @__PURE__ */ new Date();
15754
+ today.setUTCHours(0, 0, 0, 0);
15755
+ try {
15756
+ return await collection.find({
15757
+ status: "active",
15758
+ nextBillingDate: { $lte: today }
15759
+ }).sort({ nextBillingDate: 1 }).limit(BATCH_SIZE).toArray();
15760
+ } catch (error) {
15761
+ throw new BadRequestError23("Failed to get due subscriptions.");
15762
+ }
15763
+ }
15764
+ async function getFailedSubscriptions(BATCH_SIZE = 100, maxAttempts = 3) {
15765
+ try {
15766
+ return await collection.find({
15767
+ lastPaymentStatus: "failed",
15768
+ failedAttempts: { $lt: maxAttempts }
15769
+ }).limit(BATCH_SIZE).toArray();
15770
+ } catch (error) {
15771
+ throw new BadRequestError23("Failed to get failed subscriptions.");
15772
+ }
15773
+ }
15774
+ async function processSuccessfulPayment(value, session) {
15775
+ const schema3 = Joi12.object({
15776
+ _id: Joi12.string().hex().required(),
15777
+ nextBillingDate: Joi12.date().required()
15778
+ });
15779
+ const { error } = schema3.validate(value);
15780
+ if (error) {
15781
+ throw new BadRequestError23(error.message);
15782
+ }
15783
+ try {
15784
+ value._id = new ObjectId21(value._id);
15785
+ } catch (error2) {
15786
+ throw new BadRequestError23("Invalid ID.");
15787
+ }
15788
+ const date = value.nextBillingDate;
15789
+ try {
15790
+ await collection.updateOne(
15791
+ { _id: value._id },
15792
+ {
15793
+ $set: {
15794
+ nextBillingDate: new Date(
15795
+ new Date(date).setMonth(new Date(date).getMonth() + 1)
15796
+ ).toISOString(),
15797
+ lastPaymentStatus: "success",
15798
+ failedAttempts: 0
15799
+ }
15800
+ },
15801
+ { session }
15802
+ );
15803
+ return "Successfully updated subscription.";
15804
+ } catch (_) {
15805
+ throw new BadRequestError23("Failed to update subscription.");
15806
+ }
15807
+ }
15808
+ async function markSubscriptionAsFailed({ _id, failed } = {}, session) {
15809
+ const schema3 = Joi12.object({
15810
+ _id: Joi12.string().hex().required()
15811
+ });
15812
+ const { error } = schema3.validate({ _id });
15813
+ if (error) {
15814
+ throw new BadRequestError23(error.message);
15815
+ }
15816
+ try {
15817
+ _id = new ObjectId21(_id);
15818
+ } catch (error2) {
15819
+ throw new BadRequestError23("Invalid ID.");
15820
+ }
15821
+ const updateOptions = {
15822
+ $inc: { failedAttempts: 1 }
15823
+ };
15824
+ if (failed) {
15825
+ updateOptions.$set = { lastPaymentStatus: "failed" };
15826
+ }
15827
+ try {
15828
+ return await collection.updateOne({ _id }, updateOptions, { session });
15829
+ } catch (error2) {
15830
+ throw new BadRequestError23("Failed to update subscription.");
15831
+ }
15832
+ }
15833
+ async function markSubscriptionAsCanceled(_id, session) {
15834
+ const schema3 = Joi12.object({
15835
+ _id: Joi12.string().hex().required()
15836
+ });
15837
+ const { error } = schema3.validate({ _id });
15838
+ if (error) {
15839
+ throw new BadRequestError23(error.message);
15840
+ }
15841
+ try {
15842
+ _id = new ObjectId21(_id);
15843
+ } catch (error2) {
15844
+ throw new BadRequestError23("Invalid ID.");
15845
+ }
15846
+ try {
15847
+ return await collection.updateOne(
15848
+ { _id },
15849
+ {
15850
+ $set: { status: "canceled" }
15851
+ },
15852
+ { session }
15853
+ );
15854
+ } catch (error2) {
15855
+ throw new BadRequestError23("Failed to update subscription.");
15856
+ }
15857
+ }
15675
15858
  return {
15676
15859
  createIndex,
15677
15860
  createUniqueIndex,
@@ -15680,12 +15863,19 @@ function useSubscriptionRepo() {
15680
15863
  getBySubscriptionId,
15681
15864
  getByUserId,
15682
15865
  getSubscriptions,
15683
- updateStatus
15866
+ updateStatus,
15867
+ getByOrgId,
15868
+ getByAffiliateUserId,
15869
+ getDueSubscriptions,
15870
+ getFailedSubscriptions,
15871
+ processSuccessfulPayment,
15872
+ markSubscriptionAsFailed,
15873
+ markSubscriptionAsCanceled
15684
15874
  };
15685
15875
  }
15686
15876
 
15687
15877
  // src/services/subscription.service.ts
15688
- import { BadRequestError as BadRequestError31, useAtlas as useAtlas19 } from "@goweekdays/utils";
15878
+ import { BadRequestError as BadRequestError33, logger as logger15, useAtlas as useAtlas20 } from "@goweekdays/utils";
15689
15879
 
15690
15880
  // node_modules/axios/lib/helpers/bind.js
15691
15881
  function bind(fn, thisArg) {
@@ -18559,7 +18749,7 @@ validators.spelling = function spelling(correctSpelling) {
18559
18749
  return true;
18560
18750
  };
18561
18751
  };
18562
- function assertOptions(options, schema, allowUnknown) {
18752
+ function assertOptions(options, schema3, allowUnknown) {
18563
18753
  if (typeof options !== "object") {
18564
18754
  throw new AxiosError_default("options must be an object", AxiosError_default.ERR_BAD_OPTION_VALUE);
18565
18755
  }
@@ -18567,7 +18757,7 @@ function assertOptions(options, schema, allowUnknown) {
18567
18757
  let i = keys.length;
18568
18758
  while (i-- > 0) {
18569
18759
  const opt = keys[i];
18570
- const validator = schema[opt];
18760
+ const validator = schema3[opt];
18571
18761
  if (validator) {
18572
18762
  const value = options[opt];
18573
18763
  const result = value === void 0 || validator(value, opt, options);
@@ -18989,8 +19179,9 @@ var {
18989
19179
  } = axios_default;
18990
19180
 
18991
19181
  // src/services/xendit.service.ts
18992
- import { BadRequestError as BadRequestError24, logger as logger11 } from "@goweekdays/utils";
19182
+ import { AppError as AppError7, BadRequestError as BadRequestError24, logger as logger11 } from "@goweekdays/utils";
18993
19183
  import { ObjectId as ObjectId22 } from "mongodb";
19184
+ import Joi13 from "joi";
18994
19185
  function useXenditService() {
18995
19186
  const basicAuth = Buffer.from(`${XENDIT_SECRET_KEY}:`).toString("base64");
18996
19187
  const axios2 = axios_default.create({
@@ -19149,7 +19340,8 @@ function useXenditService() {
19149
19340
  amount = 0,
19150
19341
  paymentMethod = "",
19151
19342
  description = "",
19152
- interval = "MONTH"
19343
+ interval = "MONTH",
19344
+ seats = 1
19153
19345
  } = {}) {
19154
19346
  try {
19155
19347
  const res = await axios2.post("/recurring/plans", {
@@ -19182,7 +19374,9 @@ function useXenditService() {
19182
19374
  },
19183
19375
  failed_cycle_action: "STOP",
19184
19376
  immediate_action_type: "FULL_AMOUNT",
19185
- metadata: null,
19377
+ metadata: {
19378
+ seats
19379
+ },
19186
19380
  description
19187
19381
  });
19188
19382
  return res.data;
@@ -19209,6 +19403,52 @@ function useXenditService() {
19209
19403
  throw new BadRequestError24("Failed to get subscription status.");
19210
19404
  }
19211
19405
  }
19406
+ async function getSubscription(id) {
19407
+ try {
19408
+ const res = await axios2.get(`/recurring/plans/${id}`);
19409
+ return res.data;
19410
+ } catch (error) {
19411
+ throw new BadRequestError24("Failed to get subscription.");
19412
+ }
19413
+ }
19414
+ async function getSubscriptionCycles(id) {
19415
+ try {
19416
+ const res = await axios2.get(`/recurring/plans/${id}/cycles`);
19417
+ return res.data;
19418
+ } catch (error) {
19419
+ throw new BadRequestError24("Failed to get subscription cycles.");
19420
+ }
19421
+ }
19422
+ async function pay(value) {
19423
+ try {
19424
+ const schema3 = Joi13.object({
19425
+ amount: Joi13.number().positive().min(0).required(),
19426
+ currency: Joi13.string().required(),
19427
+ payment_method_id: Joi13.string().required(),
19428
+ customer_id: Joi13.string().required(),
19429
+ description: Joi13.string().optional().allow("", null),
19430
+ metadata: Joi13.object().optional()
19431
+ });
19432
+ const { error } = schema3.validate(value);
19433
+ if (error) {
19434
+ throw new BadRequestError24(error.message);
19435
+ }
19436
+ const res = await axios2.post("/payment_requests", {
19437
+ amount: value.amount,
19438
+ currency: value.currency,
19439
+ payment_method_id: value.payment_method_id,
19440
+ customer_id: value.customer_id,
19441
+ description: value.description ?? "",
19442
+ metadata: value.metadata ?? {}
19443
+ });
19444
+ return res.data;
19445
+ } catch (error) {
19446
+ if (error instanceof AppError7) {
19447
+ throw error;
19448
+ }
19449
+ throw new BadRequestError24("Failed to initiate payment request.");
19450
+ }
19451
+ }
19212
19452
  return {
19213
19453
  createCustomer,
19214
19454
  linkPaymentMethodEWallet,
@@ -19217,7 +19457,10 @@ function useXenditService() {
19217
19457
  linkPaymentMethodCard,
19218
19458
  eWalletSubsequentPayment,
19219
19459
  checkSubscriptionStatus,
19220
- cancelSubscription
19460
+ cancelSubscription,
19461
+ getSubscription,
19462
+ getSubscriptionCycles,
19463
+ pay
19221
19464
  };
19222
19465
  }
19223
19466
 
@@ -19257,7 +19500,8 @@ function MPaymentMethod(value) {
19257
19500
  paymentId: value.paymentId ?? "",
19258
19501
  customerId: value.customerId ?? "",
19259
19502
  number: value.number,
19260
- expiry: value.expiry ?? "",
19503
+ month_expiry: value.month_expiry ?? "",
19504
+ year_expiry: value.year_expiry ?? "",
19261
19505
  cvv: value.cvv ?? "",
19262
19506
  status: value.status ?? "active",
19263
19507
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
@@ -19406,7 +19650,7 @@ function usePaymentMethodRepo() {
19406
19650
 
19407
19651
  // src/repositories/organization.repository.ts
19408
19652
  import {
19409
- AppError as AppError7,
19653
+ AppError as AppError8,
19410
19654
  BadRequestError as BadRequestError28,
19411
19655
  InternalServerError as InternalServerError20,
19412
19656
  logger as logger13,
@@ -19416,23 +19660,23 @@ import {
19416
19660
 
19417
19661
  // src/models/organization.model.ts
19418
19662
  import { BadRequestError as BadRequestError27 } from "@goweekdays/utils";
19419
- import Joi11 from "joi";
19663
+ import Joi14 from "joi";
19420
19664
  import { ObjectId as ObjectId25 } from "mongodb";
19421
19665
  function MOrg(value) {
19422
- const schema = Joi11.object({
19423
- _id: Joi11.string().hex().optional().allow("", null),
19424
- name: Joi11.string().required(),
19425
- email: Joi11.string().email().required(),
19426
- contact: Joi11.string().required(),
19427
- type: Joi11.string().required(),
19428
- busInst: Joi11.string().optional().allow("", null),
19429
- description: Joi11.string().optional().allow("", null),
19430
- status: Joi11.string().optional().allow("", null),
19431
- createdAt: Joi11.string().optional().allow("", null),
19432
- updatedAt: Joi11.string().optional().allow("", null),
19433
- deletedAt: Joi11.string().optional().allow("", null)
19666
+ const schema3 = Joi14.object({
19667
+ _id: Joi14.string().hex().optional().allow("", null),
19668
+ name: Joi14.string().required(),
19669
+ email: Joi14.string().email().required(),
19670
+ contact: Joi14.string().required(),
19671
+ type: Joi14.string().required(),
19672
+ busInst: Joi14.string().optional().allow("", null),
19673
+ description: Joi14.string().optional().allow("", null),
19674
+ status: Joi14.string().optional().allow("", null),
19675
+ createdAt: Joi14.string().optional().allow("", null),
19676
+ updatedAt: Joi14.string().optional().allow("", null),
19677
+ deletedAt: Joi14.string().optional().allow("", null)
19434
19678
  });
19435
- const { error } = schema.validate(value);
19679
+ const { error } = schema3.validate(value);
19436
19680
  if (error) {
19437
19681
  throw new BadRequestError27(error.message);
19438
19682
  }
@@ -19508,7 +19752,7 @@ function useOrgRepo() {
19508
19752
  level: "error",
19509
19753
  message: error.message
19510
19754
  });
19511
- if (error instanceof AppError7) {
19755
+ if (error instanceof AppError8) {
19512
19756
  throw error;
19513
19757
  } else {
19514
19758
  const isDuplicated = error.message.includes("duplicate");
@@ -19568,7 +19812,7 @@ function useOrgRepo() {
19568
19812
  }
19569
19813
  return result;
19570
19814
  } catch (error) {
19571
- if (error instanceof AppError7) {
19815
+ if (error instanceof AppError8) {
19572
19816
  throw error;
19573
19817
  } else {
19574
19818
  throw new InternalServerError20("Failed to get organization.");
@@ -19583,7 +19827,7 @@ function useOrgRepo() {
19583
19827
  }
19584
19828
  return result;
19585
19829
  } catch (error) {
19586
- if (error instanceof AppError7) {
19830
+ if (error instanceof AppError8) {
19587
19831
  throw error;
19588
19832
  } else {
19589
19833
  throw new InternalServerError20("Failed to get organization.");
@@ -19721,27 +19965,205 @@ function useAddressRepo() {
19721
19965
  };
19722
19966
  }
19723
19967
 
19968
+ // src/repositories/order.repository.ts
19969
+ import {
19970
+ AppError as AppError9,
19971
+ BadRequestError as BadRequestError32,
19972
+ InternalServerError as InternalServerError21,
19973
+ logger as logger14,
19974
+ paginate as paginate11,
19975
+ useAtlas as useAtlas19
19976
+ } from "@goweekdays/utils";
19977
+
19978
+ // src/models/order.model.ts
19979
+ import { ObjectId as ObjectId29 } from "mongodb";
19980
+
19981
+ // src/validations/order.schema.ts
19982
+ import Joi15 from "joi";
19983
+ var schema = Joi15.object({
19984
+ _id: Joi15.string().hex().optional().allow("", null),
19985
+ payment: Joi15.string().required(),
19986
+ user: Joi15.string().hex().required(),
19987
+ org: Joi15.string().hex().optional().allow("", null),
19988
+ type: Joi15.string().required(),
19989
+ amount: Joi15.number().positive().min(0).required(),
19990
+ currency: Joi15.string().required(),
19991
+ description: Joi15.string().optional().allow("", null),
19992
+ metadata: Joi15.object({
19993
+ subscriptionId: Joi15.string().hex().optional().allow("", null),
19994
+ cycle: Joi15.number().optional().allow("", null),
19995
+ seats: Joi15.number().optional().allow("", null),
19996
+ promoCode: Joi15.string().optional().allow("", null)
19997
+ }).optional().allow("", null),
19998
+ status: Joi15.string().optional().allow("", null),
19999
+ createdAt: Joi15.string().optional().allow("", null),
20000
+ updatedAt: Joi15.string().optional().allow("", null),
20001
+ deletedAt: Joi15.string().optional().allow("", null)
20002
+ });
20003
+
20004
+ // src/models/order.model.ts
20005
+ import { BadRequestError as BadRequestError31 } from "@goweekdays/utils";
20006
+ function MOrder(value) {
20007
+ const { error } = schema.validate(value);
20008
+ if (error) {
20009
+ throw new BadRequestError31(error.message);
20010
+ }
20011
+ if (value._id) {
20012
+ try {
20013
+ value._id = new ObjectId29(value._id);
20014
+ } catch (error2) {
20015
+ throw new BadRequestError31("Invalid ID.");
20016
+ }
20017
+ }
20018
+ if (value.user) {
20019
+ try {
20020
+ value.user = new ObjectId29(value.user);
20021
+ } catch (error2) {
20022
+ throw new BadRequestError31("Invalid user ID.");
20023
+ }
20024
+ }
20025
+ if (value.org) {
20026
+ try {
20027
+ value.org = new ObjectId29(value.org);
20028
+ } catch (error2) {
20029
+ throw new BadRequestError31("Invalid org ID.");
20030
+ }
20031
+ }
20032
+ if (value.metadata?.subscriptionId) {
20033
+ try {
20034
+ value.metadata.subscriptionId = new ObjectId29(
20035
+ value.metadata.subscriptionId
20036
+ );
20037
+ } catch (error2) {
20038
+ throw new BadRequestError31("Invalid subscription ID.");
20039
+ }
20040
+ }
20041
+ return {
20042
+ _id: value._id,
20043
+ payment: value.payment,
20044
+ user: value.user ?? "",
20045
+ org: value.org ?? "",
20046
+ type: value.type,
20047
+ amount: value.amount,
20048
+ currency: value.currency,
20049
+ description: value.description ?? "",
20050
+ metadata: value.metadata ?? {},
20051
+ status: value.status ?? "succeeded",
20052
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
20053
+ updatedAt: value.updatedAt ?? "",
20054
+ deletedAt: value.deletedAt ?? ""
20055
+ };
20056
+ }
20057
+
20058
+ // src/repositories/order.repository.ts
20059
+ import { ObjectId as ObjectId30 } from "mongodb";
20060
+ function useOrderRepo() {
20061
+ const db = useAtlas19.getDb();
20062
+ if (!db) {
20063
+ throw new InternalServerError21("Unable to connect to server.");
20064
+ }
20065
+ const collection = db.collection("orders");
20066
+ function createIndex() {
20067
+ try {
20068
+ collection.createIndexes([
20069
+ { key: { "metadata.subscriptionId": 1 } },
20070
+ { key: { status: 1 } },
20071
+ { key: { type: 1 } }
20072
+ ]);
20073
+ } catch (error) {
20074
+ throw new Error("Failed to create index for promo code.");
20075
+ }
20076
+ }
20077
+ function add(value, session) {
20078
+ try {
20079
+ value = MOrder(value);
20080
+ collection.insertOne(value, { session });
20081
+ } catch (error) {
20082
+ logger14.log({ level: "error", message: `${error}` });
20083
+ if (error instanceof AppError9) {
20084
+ throw error;
20085
+ }
20086
+ throw new InternalServerError21("Internal server error.");
20087
+ }
20088
+ }
20089
+ async function getOrders({
20090
+ search = "",
20091
+ page = 1,
20092
+ limit = 10,
20093
+ sort = {},
20094
+ status = "active",
20095
+ type = "",
20096
+ id = ""
20097
+ } = {}) {
20098
+ page = page > 0 ? page - 1 : 0;
20099
+ const query = { status };
20100
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
20101
+ if (search) {
20102
+ query.$text = { $search: search };
20103
+ }
20104
+ if (type) {
20105
+ query.type = type;
20106
+ }
20107
+ if (id) {
20108
+ try {
20109
+ query["metadata.subscriptionId"] = new ObjectId30(id);
20110
+ } catch (error) {
20111
+ throw new BadRequestError32("Invalid subscription ID.");
20112
+ }
20113
+ }
20114
+ try {
20115
+ const items = await collection.aggregate([
20116
+ { $match: query },
20117
+ { $sort: sort },
20118
+ { $skip: page * limit },
20119
+ { $limit: limit }
20120
+ ]).toArray();
20121
+ const length = await collection.countDocuments(query);
20122
+ return paginate11(items, page, limit, length);
20123
+ } catch (error) {
20124
+ logger14.log({ level: "error", message: `${error}` });
20125
+ throw new InternalServerError21("Internal server error.");
20126
+ }
20127
+ }
20128
+ return {
20129
+ createIndex,
20130
+ add,
20131
+ getOrders
20132
+ };
20133
+ }
20134
+
19724
20135
  // src/services/subscription.service.ts
19725
20136
  function useSubscriptionService() {
19726
- const { getByUserId: _getByUserId, add } = useSubscriptionRepo();
20137
+ const {
20138
+ getByUserId: _getByUserId,
20139
+ add,
20140
+ getByOrgId: _getByOrgId,
20141
+ getDueSubscriptions,
20142
+ processSuccessfulPayment,
20143
+ markSubscriptionAsFailed,
20144
+ getFailedSubscriptions,
20145
+ markSubscriptionAsCanceled
20146
+ } = useSubscriptionRepo();
19727
20147
  const { getUserById: _getUserByUserId, updateUserFieldById } = useUserRepo();
19728
- const { initSubscription, checkSubscriptionStatus } = useXenditService();
19729
- const { add: addPaymentMethod, getByPaymentMethodId } = usePaymentMethodRepo();
20148
+ const {
20149
+ checkSubscriptionStatus,
20150
+ getSubscription,
20151
+ getSubscriptionCycles,
20152
+ pay
20153
+ } = useXenditService();
20154
+ const { add: addPaymentMethod } = usePaymentMethodRepo();
19730
20155
  const { add: addOrg } = useOrgRepo();
19731
20156
  const { add: addAddress } = useAddressRepo();
19732
20157
  const { addRole } = useRoleRepo();
19733
20158
  const { add: addMember } = useMemberRepo();
20159
+ const { add: addOrder } = useOrderRepo();
19734
20160
  async function createOrgSubscription(value) {
19735
- const session = useAtlas19.getClient()?.startSession();
20161
+ const session = useAtlas20.getClient()?.startSession();
19736
20162
  session?.startTransaction();
19737
20163
  try {
19738
20164
  const _user = await _getUserByUserId(value.user);
19739
20165
  if (!_user) {
19740
- throw new BadRequestError31("User not found.");
19741
- }
19742
- const payment = await getByPaymentMethodId(value.payment_method_id);
19743
- if (!payment) {
19744
- throw new BadRequestError31("Payment method not found.");
20166
+ throw new BadRequestError33("User not found.");
19745
20167
  }
19746
20168
  const org = await addOrg(value.organization, session);
19747
20169
  const role = await addRole(
@@ -19770,27 +20192,62 @@ function useSubscriptionService() {
19770
20192
  session
19771
20193
  );
19772
20194
  }
19773
- payment.user = "";
19774
- payment.org = org;
19775
- delete payment._id;
19776
- await addPaymentMethod(payment, session);
19777
- value.billingAddress.org = org;
19778
- await addAddress(value.billingAddress, session);
19779
- const subscription = await initSubscription({
19780
- customer: value.customer_id,
19781
- paymentMethod: value.payment_method_id,
19782
- amount: value.amount,
19783
- description: "GoWeekdays Organization Monthly Subscription."
19784
- });
19785
- await add(
20195
+ await addPaymentMethod(
19786
20196
  {
19787
20197
  org,
19788
- subscriptionId: subscription.id
20198
+ paymentId: value.payment_method_id,
20199
+ customerId: value.customer_id,
20200
+ type: value.payment_method_type,
20201
+ name: value.payment_method_channel,
20202
+ number: value.payment_method_number,
20203
+ month_expiry: value.payment_method_expiry_month,
20204
+ year_expiry: value.payment_method_expiry_year,
20205
+ cvv: value.payment_method_cvv
19789
20206
  },
19790
20207
  session
19791
20208
  );
19792
- await session?.commitTransaction();
19793
- return "Subscription created successfully.";
20209
+ value.billingAddress.org = org;
20210
+ await addAddress(value.billingAddress, session);
20211
+ const description = "GoWeekdays Organization Monthly Subscription.";
20212
+ const subscription = await add(
20213
+ {
20214
+ org: org.toString(),
20215
+ customerId: value.customer_id,
20216
+ paymentMethodId: value.payment_method_id,
20217
+ amount: value.amount,
20218
+ currency: value.currency,
20219
+ type: "organization",
20220
+ description,
20221
+ seats: value.seats,
20222
+ billingCycle: "monthly"
20223
+ },
20224
+ session
20225
+ );
20226
+ const payment = await pay({
20227
+ customer_id: value.customer_id,
20228
+ payment_method_id: value.payment_method_id,
20229
+ amount: value.amount,
20230
+ currency: value.currency,
20231
+ description
20232
+ });
20233
+ await addOrder(
20234
+ {
20235
+ payment: payment.id,
20236
+ user: value.user,
20237
+ org: org.toString(),
20238
+ type: "organization",
20239
+ amount: value.amount,
20240
+ currency: value.currency,
20241
+ description,
20242
+ metadata: { subscriptionId: subscription.toString() }
20243
+ },
20244
+ session
20245
+ );
20246
+ await session?.commitTransaction();
20247
+ return {
20248
+ message: "Subscription created successfully.",
20249
+ data: { org: org.toString() }
20250
+ };
19794
20251
  } catch (error) {
19795
20252
  await session?.abortTransaction();
19796
20253
  throw error;
@@ -19798,36 +20255,55 @@ function useSubscriptionService() {
19798
20255
  session?.endSession();
19799
20256
  }
19800
20257
  }
19801
- async function createAffiliateSubscription({
19802
- user = "",
19803
- amount = 0,
19804
- payment_method_id = "",
19805
- customer_id = ""
19806
- } = {}) {
19807
- const session = useAtlas19.getClient()?.startSession();
20258
+ async function createAffiliateSubscription(value) {
20259
+ const session = useAtlas20.getClient()?.startSession();
19808
20260
  session?.startTransaction();
19809
20261
  try {
19810
- const _user = await _getUserByUserId(user);
20262
+ const _user = await _getUserByUserId(value.user);
19811
20263
  if (!_user) {
19812
- throw new BadRequestError31("User not found.");
20264
+ throw new BadRequestError33("User not found.");
19813
20265
  }
19814
- const subscription = await initSubscription({
19815
- customer: customer_id,
19816
- paymentMethod: payment_method_id,
19817
- amount,
19818
- description: "GoWeekdays Affiliate Annual Subscription.",
19819
- interval: "YEAR"
19820
- });
19821
- await add(
20266
+ await addAddress(value.billingAddress, session);
20267
+ const description = "GoWeekdays affiliate yearly Subscription.";
20268
+ const subscription = await add(
19822
20269
  {
19823
- user,
19824
- subscriptionId: subscription.id
20270
+ user: value.user,
20271
+ customerId: value.customer_id,
20272
+ paymentMethodId: value.payment_method_id,
20273
+ amount: value.amount,
20274
+ currency: value.currency,
20275
+ type: "affiliate",
20276
+ description,
20277
+ billingCycle: "yearly"
20278
+ },
20279
+ session
20280
+ );
20281
+ let payment = {};
20282
+ if (value.amount) {
20283
+ payment = await pay({
20284
+ customer_id: value.customer_id,
20285
+ payment_method_id: value.payment_method_id,
20286
+ amount: value.amount,
20287
+ currency: value.currency,
20288
+ description
20289
+ });
20290
+ }
20291
+ await addOrder(
20292
+ {
20293
+ payment: payment.id,
20294
+ user: value.user,
20295
+ type: "affiliate",
20296
+ amount: value.amount,
20297
+ currency: value.currency,
20298
+ description,
20299
+ metadata: { subscriptionId: subscription.toString() }
19825
20300
  },
19826
20301
  session
19827
20302
  );
19828
20303
  await session?.commitTransaction();
19829
20304
  return "Subscription created successfully.";
19830
20305
  } catch (error) {
20306
+ console.log(error);
19831
20307
  await session?.abortTransaction();
19832
20308
  throw error;
19833
20309
  } finally {
@@ -19838,9 +20314,10 @@ function useSubscriptionService() {
19838
20314
  try {
19839
20315
  const subscription = await _getByUserId(id);
19840
20316
  if (!subscription) {
19841
- throw new BadRequestError31("Subscription not found.");
20317
+ throw new BadRequestError33("Subscription not found.");
19842
20318
  }
19843
- return subscription;
20319
+ const customerSubscription = await getSubscription(id);
20320
+ return customerSubscription;
19844
20321
  } catch (error) {
19845
20322
  throw error;
19846
20323
  }
@@ -19853,57 +20330,204 @@ function useSubscriptionService() {
19853
20330
  );
19854
20331
  return status;
19855
20332
  } catch (error) {
19856
- throw new BadRequestError31("Failed to fetch subscription status");
20333
+ throw new BadRequestError33("Failed to fetch subscription status");
20334
+ }
20335
+ }
20336
+ async function processSubscriptions(batchSize = 100) {
20337
+ while (true) {
20338
+ const subscriptions = await getDueSubscriptions(batchSize);
20339
+ if (subscriptions.length === 0) {
20340
+ logger15.log({
20341
+ level: "info",
20342
+ message: "No more subscriptions to process."
20343
+ });
20344
+ break;
20345
+ }
20346
+ await Promise.allSettled(
20347
+ subscriptions.map(async (sub) => {
20348
+ const session = useAtlas20.getClient()?.startSession();
20349
+ session?.startTransaction();
20350
+ try {
20351
+ const payment = await pay({
20352
+ customer_id: sub.customerId,
20353
+ payment_method_id: sub.paymentMethodId,
20354
+ amount: sub.amount,
20355
+ currency: sub.currency,
20356
+ description: "GoWeekdays Monthly Subscription"
20357
+ });
20358
+ await addOrder(
20359
+ {
20360
+ payment: payment.id,
20361
+ user: sub.user,
20362
+ org: sub.org,
20363
+ type: "organization",
20364
+ amount: sub.amount,
20365
+ currency: sub.currency,
20366
+ description: "GoWeekdays Monthly Subscription",
20367
+ metadata: { subscriptionId: sub._id }
20368
+ },
20369
+ session
20370
+ );
20371
+ await processSuccessfulPayment(
20372
+ { _id: sub._id, nextBillingDate: sub.nextBillingDate },
20373
+ session
20374
+ );
20375
+ await session?.commitTransaction();
20376
+ logger15.log({
20377
+ level: "info",
20378
+ message: `Processed subscription ${sub._id} successfully.`
20379
+ });
20380
+ } catch (error) {
20381
+ await session?.abortTransaction();
20382
+ logger15.log({
20383
+ level: "error",
20384
+ message: `Failed to process ${sub._id}: ${error}`
20385
+ });
20386
+ await markSubscriptionAsFailed({
20387
+ _id: String(sub._id),
20388
+ failed: true
20389
+ });
20390
+ } finally {
20391
+ session?.endSession();
20392
+ }
20393
+ })
20394
+ );
20395
+ logger15.log({
20396
+ level: "info",
20397
+ message: "Processed a batch of subscriptions."
20398
+ });
20399
+ }
20400
+ }
20401
+ async function retryFailedPayments(batchSize = 100) {
20402
+ let hasMore = true;
20403
+ while (hasMore) {
20404
+ const failedSubs = await getFailedSubscriptions(batchSize);
20405
+ if (failedSubs.length === 0) {
20406
+ hasMore = false;
20407
+ break;
20408
+ }
20409
+ await Promise.allSettled(
20410
+ failedSubs.map(async (sub) => {
20411
+ const session = useAtlas20.getClient()?.startSession();
20412
+ session?.startTransaction();
20413
+ try {
20414
+ const payment = await pay({
20415
+ customer_id: sub.customerId,
20416
+ payment_method_id: sub.paymentMethodId,
20417
+ amount: sub.amount,
20418
+ currency: sub.currency,
20419
+ description: "GoWeekdays Monthly Subscription - Retry"
20420
+ });
20421
+ await addOrder(
20422
+ {
20423
+ payment: payment.id,
20424
+ user: sub.user,
20425
+ org: sub.org,
20426
+ type: "organization",
20427
+ amount: sub.amount,
20428
+ currency: sub.currency,
20429
+ description: "GoWeekdays Monthly Subscription",
20430
+ metadata: { subscriptionId: sub._id }
20431
+ },
20432
+ session
20433
+ );
20434
+ await processSuccessfulPayment(
20435
+ { _id: sub._id, nextBillingDate: sub.nextBillingDate },
20436
+ session
20437
+ );
20438
+ await session?.commitTransaction();
20439
+ logger15.log({
20440
+ level: "info",
20441
+ message: `Successfully retried subscription ${sub._id}.`
20442
+ });
20443
+ } catch (error) {
20444
+ await session?.abortTransaction();
20445
+ logger15.log({
20446
+ level: "error",
20447
+ message: `Retry failed for ${sub._id}: ${error}`
20448
+ });
20449
+ await markSubscriptionAsFailed({ _id: String(sub._id) });
20450
+ if (sub.failedAttempts && sub.failedAttempts + 1 >= 3) {
20451
+ await markSubscriptionAsCanceled(String(sub._id));
20452
+ logger15.log({
20453
+ level: "info",
20454
+ message: `Subscription ${sub._id} canceled after max retry attempts.`
20455
+ });
20456
+ }
20457
+ } finally {
20458
+ session?.endSession();
20459
+ }
20460
+ })
20461
+ );
20462
+ logger15.log({
20463
+ level: "info",
20464
+ message: `Processed batch of ${failedSubs.length}.`
20465
+ });
19857
20466
  }
20467
+ logger15.log({ level: "info", message: "All failed payments retried." });
19858
20468
  }
19859
20469
  return {
19860
20470
  getByUserId,
19861
20471
  getStatusByUser,
19862
20472
  createAffiliateSubscription,
19863
- createOrgSubscription
20473
+ createOrgSubscription,
20474
+ processSubscriptions,
20475
+ retryFailedPayments
19864
20476
  };
19865
20477
  }
19866
20478
 
19867
20479
  // src/controllers/subscription.controller.ts
19868
- import Joi13 from "joi";
19869
- import { BadRequestError as BadRequestError32 } from "@goweekdays/utils";
20480
+ import Joi17 from "joi";
20481
+ import { BadRequestError as BadRequestError34 } from "@goweekdays/utils";
19870
20482
 
19871
20483
  // src/validations/subscription.schema.ts
19872
- import Joi12 from "joi";
20484
+ import Joi16 from "joi";
19873
20485
  function useSubscriptionSchema() {
19874
- const schema = Joi12.object({
19875
- user: Joi12.string().required(),
19876
- amount: Joi12.number().required(),
19877
- customer_id: Joi12.string().required(),
19878
- payment_method_id: Joi12.string().required(),
19879
- currency: Joi12.string().optional().allow("", null),
19880
- organization: Joi12.object({
19881
- name: Joi12.string().required(),
19882
- description: Joi12.string().optional().allow("", null),
19883
- type: Joi12.string().allow("personal", "business").required(),
19884
- email: Joi12.string().email().required(),
19885
- contact: Joi12.string().required(),
19886
- busInst: Joi12.string().optional().allow(null, "")
19887
- }).required(),
19888
- billingAddress: Joi12.object({
19889
- type: Joi12.string().required(),
19890
- country: Joi12.string().required(),
19891
- address: Joi12.string().required(),
19892
- continuedAddress: Joi12.string().optional().allow(null, ""),
19893
- city: Joi12.string().required(),
19894
- province: Joi12.string().required(),
19895
- postalCode: Joi12.string().required(),
19896
- taxId: Joi12.string().optional().allow(null, "")
20486
+ const schema3 = Joi16.object({
20487
+ user: Joi16.string().required().min(0),
20488
+ amount: Joi16.number().required(),
20489
+ customer_id: Joi16.string().required(),
20490
+ payment_method_id: Joi16.string().required(),
20491
+ payment_method_type: Joi16.string().required(),
20492
+ payment_method_number: Joi16.string().required(),
20493
+ payment_method_channel: Joi16.string().required(),
20494
+ payment_method_month_expiry: Joi16.string().optional().allow(null, ""),
20495
+ payment_method_year_expiry: Joi16.string().optional().allow(null, ""),
20496
+ payment_method_cvv: Joi16.string().optional().allow(null, ""),
20497
+ currency: Joi16.string().optional().allow("", null),
20498
+ seats: Joi16.number().optional().min(0).allow(null),
20499
+ organization: Joi16.object({
20500
+ name: Joi16.string().required(),
20501
+ description: Joi16.string().optional().allow("", null),
20502
+ type: Joi16.string().allow("personal", "business").required(),
20503
+ email: Joi16.string().email().required(),
20504
+ contact: Joi16.string().required(),
20505
+ busInst: Joi16.string().optional().allow(null, "")
20506
+ }).optional().allow({}),
20507
+ billingAddress: Joi16.object({
20508
+ type: Joi16.string().required(),
20509
+ country: Joi16.string().required(),
20510
+ address: Joi16.string().required(),
20511
+ continuedAddress: Joi16.string().optional().allow(null, ""),
20512
+ city: Joi16.string().required(),
20513
+ province: Joi16.string().required(),
20514
+ postalCode: Joi16.string().required(),
20515
+ taxId: Joi16.string().optional().allow(null, "")
19897
20516
  }).required()
19898
20517
  });
19899
20518
  return {
19900
- schema
20519
+ schema: schema3
19901
20520
  };
19902
20521
  }
19903
20522
 
19904
20523
  // src/controllers/subscription.controller.ts
19905
20524
  function useSubscriptionController() {
19906
- const { add: _add, getSubscriptions: _getSubscriptions } = useSubscriptionRepo();
20525
+ const {
20526
+ add: _add,
20527
+ getSubscriptions: _getSubscriptions,
20528
+ getByAffiliateUserId: _getByAffiliateUserId,
20529
+ getByOrgId: _getByOrgId
20530
+ } = useSubscriptionRepo();
19907
20531
  const {
19908
20532
  getByUserId: _getByUserId,
19909
20533
  getStatusByUser: _getStatusByUser,
@@ -19912,13 +20536,13 @@ function useSubscriptionController() {
19912
20536
  } = useSubscriptionService();
19913
20537
  async function add(req, res, next) {
19914
20538
  const value = req.body;
19915
- const validation = Joi13.object({
19916
- user: Joi13.string().required(),
19917
- subscriptionId: Joi13.string().required()
20539
+ const validation = Joi17.object({
20540
+ user: Joi17.string().required(),
20541
+ subscriptionId: Joi17.string().required()
19918
20542
  });
19919
20543
  const { error } = validation.validate(value);
19920
20544
  if (error) {
19921
- next(new BadRequestError32(error.message));
20545
+ next(new BadRequestError34(error.message));
19922
20546
  }
19923
20547
  try {
19924
20548
  const value2 = req.body;
@@ -19931,10 +20555,10 @@ function useSubscriptionController() {
19931
20555
  }
19932
20556
  async function getByUserId(req, res, next) {
19933
20557
  const id = req.params.id;
19934
- const validation = Joi13.string().required();
20558
+ const validation = Joi17.string().required();
19935
20559
  const { error } = validation.validate(id);
19936
20560
  if (error) {
19937
- next(new BadRequestError32(error.message));
20561
+ next(new BadRequestError34(error.message));
19938
20562
  }
19939
20563
  try {
19940
20564
  const subscription = await _getByUserId(id);
@@ -19944,18 +20568,48 @@ function useSubscriptionController() {
19944
20568
  next(error2);
19945
20569
  }
19946
20570
  }
20571
+ async function getByAffiliateUserId(req, res, next) {
20572
+ const id = req.params.id;
20573
+ const validation = Joi17.string().required();
20574
+ const { error } = validation.validate(id);
20575
+ if (error) {
20576
+ next(new BadRequestError34(error.message));
20577
+ }
20578
+ try {
20579
+ const subscription = await _getByAffiliateUserId(id);
20580
+ res.json(subscription);
20581
+ return;
20582
+ } catch (error2) {
20583
+ next(error2);
20584
+ }
20585
+ }
20586
+ async function getByOrgId(req, res, next) {
20587
+ const id = req.params.id;
20588
+ const validation = Joi17.string().required();
20589
+ const { error } = validation.validate(id);
20590
+ if (error) {
20591
+ next(new BadRequestError34(error.message));
20592
+ }
20593
+ try {
20594
+ const subscription = await _getByOrgId(id);
20595
+ res.json(subscription);
20596
+ return;
20597
+ } catch (error2) {
20598
+ next(error2);
20599
+ }
20600
+ }
19947
20601
  async function getSubscriptions(req, res, next) {
19948
20602
  const status = req.query.status ?? "";
19949
20603
  const search = req.query.search ?? "";
19950
20604
  const page = Number(req.query.page) ?? 1;
19951
- const validation = Joi13.object({
19952
- status: Joi13.string().required(),
19953
- search: Joi13.string().optional().allow("", null),
19954
- page: Joi13.number().required()
20605
+ const validation = Joi17.object({
20606
+ status: Joi17.string().required(),
20607
+ search: Joi17.string().optional().allow("", null),
20608
+ page: Joi17.number().required()
19955
20609
  });
19956
20610
  const { error } = validation.validate({ status, search, page });
19957
20611
  if (error) {
19958
- next(new BadRequestError32(error.message));
20612
+ next(new BadRequestError34(error.message));
19959
20613
  }
19960
20614
  try {
19961
20615
  const subscriptions = await _getSubscriptions({ status, search, page });
@@ -19967,10 +20621,10 @@ function useSubscriptionController() {
19967
20621
  }
19968
20622
  async function getSubscriptionStatus(req, res, next) {
19969
20623
  const id = req.params.id;
19970
- const validation = Joi13.string().required();
20624
+ const validation = Joi17.string().required();
19971
20625
  const { error } = validation.validate(id);
19972
20626
  if (error) {
19973
- next(new BadRequestError32(error.message));
20627
+ next(new BadRequestError34(error.message));
19974
20628
  }
19975
20629
  try {
19976
20630
  const status = await _getStatusByUser(id);
@@ -19980,37 +20634,17 @@ function useSubscriptionController() {
19980
20634
  next(error2);
19981
20635
  }
19982
20636
  }
20637
+ const { schema: subscriptionSchema } = useSubscriptionSchema();
19983
20638
  async function createAffiliateSubscription(req, res, next) {
19984
- const amount = req.body.amount ?? 0;
19985
- const payment_method_id = req.body.payment_method_id ?? "";
19986
- const customer_id = req.body.customer_id ?? "";
19987
- const currency = req.body.currency ?? "PHP";
19988
- const user = req.headers["user"];
19989
- const validation = Joi13.object({
19990
- user: Joi13.string().required(),
19991
- amount: Joi13.number().required(),
19992
- customer_id: Joi13.string().required(),
19993
- payment_method_id: Joi13.string().required(),
19994
- currency: Joi13.string().optional().allow("", null)
19995
- });
19996
- const { error } = validation.validate({
19997
- user,
19998
- amount,
19999
- customer_id,
20000
- payment_method_id,
20001
- currency
20002
- });
20639
+ const value = req.body;
20640
+ value.user = req.headers["user"];
20641
+ const { error } = subscriptionSchema.validate(value);
20003
20642
  if (error) {
20004
- next(new BadRequestError32(error.message));
20643
+ next(new BadRequestError34(error.message));
20005
20644
  return;
20006
20645
  }
20007
20646
  try {
20008
- const id = await _createAffiliateSubscription({
20009
- user,
20010
- amount,
20011
- customer_id,
20012
- payment_method_id
20013
- });
20647
+ const id = await _createAffiliateSubscription(value);
20014
20648
  res.json({ message: "Successfully added subscription.", id });
20015
20649
  return;
20016
20650
  } catch (error2) {
@@ -20019,18 +20653,17 @@ function useSubscriptionController() {
20019
20653
  return;
20020
20654
  }
20021
20655
  }
20022
- const { schema: subscriptionSchema } = useSubscriptionSchema();
20023
20656
  async function createOrgSubscription(req, res, next) {
20024
20657
  const value = req.body;
20025
20658
  value.user = req.headers["user"];
20026
20659
  const { error } = subscriptionSchema.validate(value);
20027
20660
  if (error) {
20028
- next(new BadRequestError32(error.message));
20661
+ next(new BadRequestError34(error.message));
20029
20662
  return;
20030
20663
  }
20031
20664
  try {
20032
- const id = await _createOrgSubscription(value);
20033
- res.json({ message: "Successfully added subscription.", id });
20665
+ const _res = await _createOrgSubscription(value);
20666
+ res.json(_res);
20034
20667
  return;
20035
20668
  } catch (error2) {
20036
20669
  next(error2);
@@ -20040,6 +20673,8 @@ function useSubscriptionController() {
20040
20673
  return {
20041
20674
  add,
20042
20675
  getByUserId,
20676
+ getByOrgId,
20677
+ getByAffiliateUserId,
20043
20678
  getSubscriptions,
20044
20679
  getSubscriptionStatus,
20045
20680
  createAffiliateSubscription,
@@ -20048,7 +20683,7 @@ function useSubscriptionController() {
20048
20683
  }
20049
20684
 
20050
20685
  // src/services/payment-method.service.ts
20051
- import { BadRequestError as BadRequestError33, useAtlas as useAtlas20 } from "@goweekdays/utils";
20686
+ import { BadRequestError as BadRequestError35, useAtlas as useAtlas21 } from "@goweekdays/utils";
20052
20687
  function usePaymentMethodService() {
20053
20688
  const { createCustomer, linkPaymentMethodEWallet, linkPaymentMethodCard } = useXenditService();
20054
20689
  const { getUserById } = useUserRepo();
@@ -20101,7 +20736,7 @@ function usePaymentMethodService() {
20101
20736
  failure_return_url = "",
20102
20737
  cancel_return_url = ""
20103
20738
  } = {}) {
20104
- const session = useAtlas20.getClient()?.startSession();
20739
+ const session = useAtlas21.getClient()?.startSession();
20105
20740
  session?.startTransaction();
20106
20741
  try {
20107
20742
  const customerData = {
@@ -20111,10 +20746,10 @@ function usePaymentMethodService() {
20111
20746
  if (user) {
20112
20747
  const _user = await getUserById(user);
20113
20748
  if (!_user) {
20114
- throw new BadRequestError33("User not found.");
20749
+ throw new BadRequestError35("User not found.");
20115
20750
  }
20116
20751
  if (!_user._id) {
20117
- throw new BadRequestError33("Invalid user ID.");
20752
+ throw new BadRequestError35("Invalid user ID.");
20118
20753
  }
20119
20754
  customerData.email = _user.email;
20120
20755
  customerData.given_names = _user.firstName;
@@ -20123,7 +20758,7 @@ function usePaymentMethodService() {
20123
20758
  if (org) {
20124
20759
  const _org = await getOrgById(org);
20125
20760
  if (!_org) {
20126
- throw new BadRequestError33("Organization not found.");
20761
+ throw new BadRequestError35("Organization not found.");
20127
20762
  }
20128
20763
  customerData.email = _org.email;
20129
20764
  customerData.given_names = _org.name;
@@ -20137,20 +20772,6 @@ function usePaymentMethodService() {
20137
20772
  failure_return_url,
20138
20773
  cancel_return_url
20139
20774
  });
20140
- await add(
20141
- {
20142
- user,
20143
- org,
20144
- type,
20145
- status: "active",
20146
- paymentId: paymentMethod.id,
20147
- customerId: customer.id,
20148
- name: paymentMethod.type,
20149
- number: mobile_number
20150
- },
20151
- session
20152
- );
20153
- await session?.commitTransaction();
20154
20775
  return {
20155
20776
  paymentMethod: paymentMethod.id,
20156
20777
  customer: customer.id,
@@ -20175,15 +20796,15 @@ function usePaymentMethodService() {
20175
20796
  cardholder_name = "",
20176
20797
  currency = "PHP"
20177
20798
  } = {}) {
20178
- const session = useAtlas20.getClient()?.startSession();
20799
+ const session = useAtlas21.getClient()?.startSession();
20179
20800
  session?.startTransaction();
20180
20801
  try {
20181
20802
  const _user = await getUserById(user);
20182
20803
  if (!_user) {
20183
- throw new BadRequestError33("User not found.");
20804
+ throw new BadRequestError35("User not found.");
20184
20805
  }
20185
20806
  if (!_user._id) {
20186
- throw new BadRequestError33("Invalid user ID.");
20807
+ throw new BadRequestError35("Invalid user ID.");
20187
20808
  }
20188
20809
  const result = await linkPaymentMethodCard({
20189
20810
  card_number,
@@ -20223,8 +20844,8 @@ function usePaymentMethodService() {
20223
20844
  }
20224
20845
 
20225
20846
  // src/controllers/payment-method.controller.ts
20226
- import Joi14 from "joi";
20227
- import { BadRequestError as BadRequestError34 } from "@goweekdays/utils";
20847
+ import Joi18 from "joi";
20848
+ import { BadRequestError as BadRequestError36 } from "@goweekdays/utils";
20228
20849
  function usePaymentMethodController() {
20229
20850
  const { linkEWallet: _linkEWallet, linkCard: _linkCard } = usePaymentMethodService();
20230
20851
  async function linkEWallet(req, res, next) {
@@ -20235,14 +20856,14 @@ function usePaymentMethodController() {
20235
20856
  const success_return_url = req.body.success_return_url ?? "";
20236
20857
  const failure_return_url = req.body.failure_return_url ?? "";
20237
20858
  const cancel_return_url = req.body.cancel_return_url ?? "";
20238
- const validation = Joi14.object({
20239
- user: Joi14.string().hex().optional().allow("", null),
20240
- org: Joi14.string().hex().optional().allow("", null),
20241
- mobile_number: Joi14.string().required(),
20242
- type: Joi14.string().valid("GCASH", "PAYMAYA").required(),
20243
- success_return_url: Joi14.string().uri().required(),
20244
- failure_return_url: Joi14.string().uri().required(),
20245
- cancel_return_url: Joi14.string().uri().required()
20859
+ const validation = Joi18.object({
20860
+ user: Joi18.string().hex().optional().allow("", null),
20861
+ org: Joi18.string().hex().optional().allow("", null),
20862
+ mobile_number: Joi18.string().required(),
20863
+ type: Joi18.string().valid("GCASH", "PAYMAYA").required(),
20864
+ success_return_url: Joi18.string().uri().required(),
20865
+ failure_return_url: Joi18.string().uri().required(),
20866
+ cancel_return_url: Joi18.string().uri().required()
20246
20867
  }).custom((value, helpers) => {
20247
20868
  if (!value.user && !value.org) {
20248
20869
  return helpers.error("any.invalid", {
@@ -20261,7 +20882,7 @@ function usePaymentMethodController() {
20261
20882
  cancel_return_url
20262
20883
  });
20263
20884
  if (error) {
20264
- next(new BadRequestError34(error.message));
20885
+ next(new BadRequestError36(error.message));
20265
20886
  }
20266
20887
  try {
20267
20888
  const result = await _linkEWallet({
@@ -20290,17 +20911,17 @@ function usePaymentMethodController() {
20290
20911
  const failure_return_url = req.body.failure_return_url ?? "";
20291
20912
  const cardType = req.body.cardType ?? "";
20292
20913
  const user = req.headers["user"] ?? "";
20293
- const validation = Joi14.object({
20294
- cardNumber: Joi14.string().required(),
20295
- expiryMonth: Joi14.string().required(),
20296
- expiryYear: Joi14.string().required(),
20297
- cvv: Joi14.string().required(),
20298
- cardholderName: Joi14.string().required(),
20299
- currency: Joi14.string().optional().allow("", null),
20300
- success_return_url: Joi14.string().uri().required(),
20301
- failure_return_url: Joi14.string().uri().required(),
20302
- cardType: Joi14.string().required(),
20303
- user: Joi14.string().hex().required()
20914
+ const validation = Joi18.object({
20915
+ cardNumber: Joi18.string().required(),
20916
+ expiryMonth: Joi18.string().required(),
20917
+ expiryYear: Joi18.string().required(),
20918
+ cvv: Joi18.string().required(),
20919
+ cardholderName: Joi18.string().required(),
20920
+ currency: Joi18.string().optional().allow("", null),
20921
+ success_return_url: Joi18.string().uri().required(),
20922
+ failure_return_url: Joi18.string().uri().required(),
20923
+ cardType: Joi18.string().required(),
20924
+ user: Joi18.string().hex().required()
20304
20925
  });
20305
20926
  const { error } = validation.validate({
20306
20927
  user,
@@ -20315,7 +20936,7 @@ function usePaymentMethodController() {
20315
20936
  failure_return_url
20316
20937
  });
20317
20938
  if (error) {
20318
- next(new BadRequestError34(error.message));
20939
+ next(new BadRequestError36(error.message));
20319
20940
  }
20320
20941
  try {
20321
20942
  const result = await _linkCard({
@@ -20339,12 +20960,12 @@ function usePaymentMethodController() {
20339
20960
  const { getByUser: _getByUser, getByOrg: _getByOrg } = usePaymentMethodRepo();
20340
20961
  async function getByUser(req, res, next) {
20341
20962
  const user = req.params.user ?? "";
20342
- const validation = Joi14.object({
20343
- user: Joi14.string().hex().required()
20963
+ const validation = Joi18.object({
20964
+ user: Joi18.string().hex().required()
20344
20965
  });
20345
20966
  const { error } = validation.validate({ user });
20346
20967
  if (error) {
20347
- next(new BadRequestError34(error.message));
20968
+ next(new BadRequestError36(error.message));
20348
20969
  }
20349
20970
  try {
20350
20971
  const result = await _getByUser(user);
@@ -20355,12 +20976,12 @@ function usePaymentMethodController() {
20355
20976
  }
20356
20977
  async function getByOrg(req, res, next) {
20357
20978
  const org = req.params.org ?? "";
20358
- const validation = Joi14.object({
20359
- org: Joi14.string().hex().required()
20979
+ const validation = Joi18.object({
20980
+ org: Joi18.string().hex().required()
20360
20981
  });
20361
20982
  const { error } = validation.validate({ org });
20362
20983
  if (error) {
20363
- next(new BadRequestError34(error.message));
20984
+ next(new BadRequestError36(error.message));
20364
20985
  }
20365
20986
  try {
20366
20987
  const result = await _getByOrg(org);
@@ -20378,27 +20999,27 @@ function usePaymentMethodController() {
20378
20999
  }
20379
21000
 
20380
21001
  // src/controllers/address.controller.ts
20381
- import { BadRequestError as BadRequestError35, NotFoundError as NotFoundError4 } from "@goweekdays/utils";
20382
- import Joi15 from "joi";
21002
+ import { BadRequestError as BadRequestError37, NotFoundError as NotFoundError4 } from "@goweekdays/utils";
21003
+ import Joi19 from "joi";
20383
21004
  function useAddressController() {
20384
21005
  const { add: _add, getByUserId: _getByUserId } = useAddressRepo();
20385
21006
  async function add(req, res, next) {
20386
21007
  const value = req.body;
20387
- const validation = Joi15.object({
20388
- type: Joi15.string().required(),
20389
- user: Joi15.string().hex().optional().allow("", null),
20390
- org: Joi15.string().hex().optional().allow("", null),
20391
- country: Joi15.string().required(),
20392
- address: Joi15.string().required(),
20393
- continuedAddress: Joi15.string().optional().allow("", null),
20394
- city: Joi15.string().required(),
20395
- province: Joi15.string().required(),
20396
- postalCode: Joi15.string().required(),
20397
- taxId: Joi15.string().optional().allow("", null)
21008
+ const validation = Joi19.object({
21009
+ type: Joi19.string().required(),
21010
+ user: Joi19.string().hex().optional().allow("", null),
21011
+ org: Joi19.string().hex().optional().allow("", null),
21012
+ country: Joi19.string().required(),
21013
+ address: Joi19.string().required(),
21014
+ continuedAddress: Joi19.string().optional().allow("", null),
21015
+ city: Joi19.string().required(),
21016
+ province: Joi19.string().required(),
21017
+ postalCode: Joi19.string().required(),
21018
+ taxId: Joi19.string().optional().allow("", null)
20398
21019
  });
20399
21020
  const { error } = validation.validate(value);
20400
21021
  if (error) {
20401
- next(new BadRequestError35(error.message));
21022
+ next(new BadRequestError37(error.message));
20402
21023
  }
20403
21024
  try {
20404
21025
  const value2 = req.body;
@@ -20411,10 +21032,10 @@ function useAddressController() {
20411
21032
  }
20412
21033
  async function getByUserId(req, res, next) {
20413
21034
  const user = req.params.user;
20414
- const validation = Joi15.string().hex().required();
21035
+ const validation = Joi19.string().hex().required();
20415
21036
  const { error } = validation.validate(user);
20416
21037
  if (error) {
20417
- next(new BadRequestError35(error.message));
21038
+ next(new BadRequestError37(error.message));
20418
21039
  }
20419
21040
  try {
20420
21041
  const address = await _getByUserId(user);
@@ -20435,14 +21056,14 @@ function useAddressController() {
20435
21056
  }
20436
21057
 
20437
21058
  // src/services/organization.service.ts
20438
- import { NotFoundError as NotFoundError5, useAtlas as useAtlas21 } from "@goweekdays/utils";
21059
+ import { NotFoundError as NotFoundError5, useAtlas as useAtlas22 } from "@goweekdays/utils";
20439
21060
  function useOrgService() {
20440
21061
  const { add: addOrg } = useOrgRepo();
20441
21062
  const { addRole } = useRoleRepo();
20442
21063
  const { add: addMember } = useMemberRepo();
20443
21064
  const { getUserById } = useUserRepo();
20444
21065
  async function createOrg({ user = "", name = "", description = "" } = {}) {
20445
- const session = useAtlas21.getClient()?.startSession();
21066
+ const session = useAtlas22.getClient()?.startSession();
20446
21067
  session?.startTransaction();
20447
21068
  try {
20448
21069
  const _user = await getUserById(user);
@@ -20490,25 +21111,25 @@ function useOrgService() {
20490
21111
  }
20491
21112
 
20492
21113
  // src/controllers/organization.controller.ts
20493
- import { BadRequestError as BadRequestError36 } from "@goweekdays/utils";
20494
- import Joi16 from "joi";
21114
+ import { BadRequestError as BadRequestError38 } from "@goweekdays/utils";
21115
+ import Joi20 from "joi";
20495
21116
  function useOrgController() {
20496
21117
  const { createOrg: _createOrg } = useOrgService();
20497
21118
  const { getByUserId: _getByUserId } = useMemberRepo();
20498
21119
  const { getByName: _getByName } = useOrgRepo();
20499
21120
  async function createOrg(req, res, next) {
20500
21121
  const value = req.body;
20501
- const validation = Joi16.object({
20502
- name: Joi16.string().required(),
20503
- type: Joi16.string().required(),
20504
- email: Joi16.string().email().required(),
20505
- contact: Joi16.string().required(),
20506
- description: Joi16.string().required(),
20507
- user: Joi16.string().hex().required()
21122
+ const validation = Joi20.object({
21123
+ name: Joi20.string().required(),
21124
+ type: Joi20.string().required(),
21125
+ email: Joi20.string().email().required(),
21126
+ contact: Joi20.string().required(),
21127
+ description: Joi20.string().required(),
21128
+ user: Joi20.string().hex().required()
20508
21129
  });
20509
21130
  const { error } = validation.validate(value);
20510
21131
  if (error) {
20511
- next(new BadRequestError36(error.message));
21132
+ next(new BadRequestError38(error.message));
20512
21133
  return;
20513
21134
  }
20514
21135
  try {
@@ -20526,23 +21147,23 @@ function useOrgController() {
20526
21147
  const user = req.headers["user"];
20527
21148
  const isPageNumber = isFinite(page);
20528
21149
  if (!isPageNumber) {
20529
- next(new BadRequestError36("Invalid page number."));
21150
+ next(new BadRequestError38("Invalid page number."));
20530
21151
  return;
20531
21152
  }
20532
21153
  const isLimitNumber = isFinite(limit);
20533
21154
  if (!isLimitNumber) {
20534
- next(new BadRequestError36("Invalid limit number."));
21155
+ next(new BadRequestError38("Invalid limit number."));
20535
21156
  return;
20536
21157
  }
20537
- const validation = Joi16.object({
20538
- user: Joi16.string().hex().required(),
20539
- page: Joi16.number().min(1).optional().allow("", null),
20540
- limit: Joi16.number().min(1).optional().allow("", null),
20541
- search: Joi16.string().optional().allow("", null)
21158
+ const validation = Joi20.object({
21159
+ user: Joi20.string().hex().required(),
21160
+ page: Joi20.number().min(1).optional().allow("", null),
21161
+ limit: Joi20.number().min(1).optional().allow("", null),
21162
+ search: Joi20.string().optional().allow("", null)
20542
21163
  });
20543
21164
  const { error } = validation.validate({ user, page, limit, search });
20544
21165
  if (error) {
20545
- next(new BadRequestError36(error.message));
21166
+ next(new BadRequestError38(error.message));
20546
21167
  return;
20547
21168
  }
20548
21169
  try {
@@ -20555,12 +21176,12 @@ function useOrgController() {
20555
21176
  }
20556
21177
  async function getByName(req, res, next) {
20557
21178
  const name = req.params.name;
20558
- const validation = Joi16.object({
20559
- name: Joi16.string().required()
21179
+ const validation = Joi20.object({
21180
+ name: Joi20.string().required()
20560
21181
  });
20561
21182
  const { error } = validation.validate({ name });
20562
21183
  if (error) {
20563
- next(new BadRequestError36(error.message));
21184
+ next(new BadRequestError38(error.message));
20564
21185
  return;
20565
21186
  }
20566
21187
  try {
@@ -20577,6 +21198,276 @@ function useOrgController() {
20577
21198
  getByName
20578
21199
  };
20579
21200
  }
21201
+
21202
+ // src/validations/promo-code.schema.ts
21203
+ import Joi21 from "joi";
21204
+ var promoTypeSchema = Joi21.string().valid("tiered", "fixed").required();
21205
+ var promoTierSchema = Joi21.object({
21206
+ min: Joi21.number().integer().min(1).required(),
21207
+ max: Joi21.number().integer().min(Joi21.ref("min")).allow(0).required(),
21208
+ price: Joi21.number().positive().required()
21209
+ });
21210
+ var schema2 = Joi21.object({
21211
+ code: Joi21.string().trim().uppercase().required(),
21212
+ description: Joi21.string().trim().optional(),
21213
+ type: promoTypeSchema,
21214
+ tiers: Joi21.alternatives().conditional("type", {
21215
+ is: "tiered",
21216
+ then: Joi21.array().items(promoTierSchema).min(1).required(),
21217
+ otherwise: Joi21.forbidden()
21218
+ }),
21219
+ fixed_rate: Joi21.alternatives().conditional("type", {
21220
+ is: "fixed",
21221
+ then: Joi21.number().required().min(0),
21222
+ otherwise: Joi21.number().integer().allow(0)
21223
+ }),
21224
+ expiresAt: Joi21.string().optional().allow(null, "")
21225
+ });
21226
+
21227
+ // src/models/promo-code.model.ts
21228
+ import { BadRequestError as BadRequestError39 } from "@goweekdays/utils";
21229
+ function MPromoCode(data) {
21230
+ const { error } = schema2.validate(data);
21231
+ if (error) {
21232
+ throw new BadRequestError39(error.message);
21233
+ }
21234
+ return {
21235
+ _id: data._id,
21236
+ code: data.code,
21237
+ description: data.description ?? "",
21238
+ type: data.type,
21239
+ tiers: data.tiers ?? [],
21240
+ fixed_rate: data.fixed_rate ?? 0,
21241
+ appliesTo: data.appliesTo ?? "",
21242
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
21243
+ expiresAt: data.expiresAt ?? "",
21244
+ assignedTo: data.assignedTo,
21245
+ status: data.status ?? "active"
21246
+ };
21247
+ }
21248
+
21249
+ // src/repositories/promo-code.repository.ts
21250
+ import {
21251
+ BadRequestError as BadRequestError40,
21252
+ InternalServerError as InternalServerError22,
21253
+ logger as logger16,
21254
+ paginate as paginate12,
21255
+ useAtlas as useAtlas23
21256
+ } from "@goweekdays/utils";
21257
+ import Joi22 from "joi";
21258
+ function usePromoCodeRepo() {
21259
+ const db = useAtlas23.getDb();
21260
+ if (!db) {
21261
+ throw new InternalServerError22("Unable to connect to server.");
21262
+ }
21263
+ const collection = db.collection("promo-codes");
21264
+ function createIndex() {
21265
+ try {
21266
+ collection.createIndexes([{ key: { code: 1 } }, { key: { type: 1 } }]);
21267
+ } catch (error) {
21268
+ throw new Error("Failed to create index for promo code.");
21269
+ }
21270
+ }
21271
+ function createUniqueIndex() {
21272
+ try {
21273
+ collection.createIndexes([{ key: { code: 1, type: 1 }, unique: true }]);
21274
+ } catch (error) {
21275
+ throw new Error("Failed to create unique index for promo code.");
21276
+ }
21277
+ }
21278
+ function add(value) {
21279
+ try {
21280
+ value = MPromoCode(value);
21281
+ collection.insertOne(value);
21282
+ } catch (error) {
21283
+ logger16.log({ level: "error", message: `${error}` });
21284
+ const isDuplicated = error.message.includes("duplicate");
21285
+ if (isDuplicated) {
21286
+ throw new BadRequestError40("Promo code already exists.");
21287
+ }
21288
+ throw new InternalServerError22("Internal server error.");
21289
+ }
21290
+ }
21291
+ function getByCode(code) {
21292
+ const schema3 = Joi22.object({
21293
+ code: Joi22.string().trim().required()
21294
+ });
21295
+ const { error } = schema3.validate({ code });
21296
+ if (error) {
21297
+ throw new BadRequestError40(error.message);
21298
+ }
21299
+ try {
21300
+ return collection.findOne({ code });
21301
+ } catch (error2) {
21302
+ throw new InternalServerError22("Internal server error.");
21303
+ }
21304
+ }
21305
+ async function getPromoCodes({
21306
+ search = "",
21307
+ page = 1,
21308
+ limit = 10,
21309
+ sort = {},
21310
+ status = "active",
21311
+ type = ""
21312
+ } = {}) {
21313
+ page = page > 0 ? page - 1 : 0;
21314
+ const query = { status };
21315
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
21316
+ if (search) {
21317
+ query.$text = { $search: search };
21318
+ }
21319
+ if (type) {
21320
+ query.type = type;
21321
+ }
21322
+ try {
21323
+ const items = await collection.aggregate([
21324
+ { $match: query },
21325
+ { $sort: sort },
21326
+ { $skip: page * limit },
21327
+ { $limit: limit }
21328
+ ]).toArray();
21329
+ const length = await collection.countDocuments(query);
21330
+ return paginate12(items, page, limit, length);
21331
+ } catch (error) {
21332
+ logger16.log({ level: "error", message: `${error}` });
21333
+ throw new InternalServerError22("Internal server error.");
21334
+ }
21335
+ }
21336
+ return {
21337
+ createIndex,
21338
+ createUniqueIndex,
21339
+ add,
21340
+ getByCode,
21341
+ getPromoCodes
21342
+ };
21343
+ }
21344
+
21345
+ // src/controllers/promo-code.controller.ts
21346
+ import {
21347
+ AppError as AppError10,
21348
+ BadRequestError as BadRequestError41,
21349
+ InternalServerError as InternalServerError23
21350
+ } from "@goweekdays/utils";
21351
+ import Joi23 from "joi";
21352
+ function usePromoCodeController() {
21353
+ const {
21354
+ add: _add,
21355
+ getByCode: _getByCode,
21356
+ getPromoCodes: _getPromoCodes
21357
+ } = usePromoCodeRepo();
21358
+ async function add(req, res, next) {
21359
+ const data = req.body;
21360
+ const { error } = schema2.validate(data);
21361
+ if (error) {
21362
+ next(new BadRequestError41(error.message));
21363
+ return;
21364
+ }
21365
+ try {
21366
+ _add(data);
21367
+ res.json({ message: "Successfully added promo code." });
21368
+ return;
21369
+ } catch (error2) {
21370
+ if (error2 instanceof AppError10) {
21371
+ next(error2);
21372
+ } else {
21373
+ next(new InternalServerError23(error2));
21374
+ }
21375
+ }
21376
+ }
21377
+ async function getByCode(req, res, next) {
21378
+ const code = req.params.code;
21379
+ const validation = Joi23.string().required();
21380
+ const { error } = validation.validate(code);
21381
+ if (error) {
21382
+ next(new BadRequestError41(error.message));
21383
+ return;
21384
+ }
21385
+ try {
21386
+ const promoCode = _getByCode(code);
21387
+ res.json({ promoCode });
21388
+ return;
21389
+ } catch (error2) {
21390
+ if (error2 instanceof AppError10) {
21391
+ next(error2);
21392
+ } else {
21393
+ next(new InternalServerError23(error2));
21394
+ }
21395
+ }
21396
+ }
21397
+ async function getPromoCodes(req, res, next) {
21398
+ const page = req.query.page;
21399
+ const limit = req.query.limit;
21400
+ const search = req.query.search;
21401
+ const status = req.query.status;
21402
+ const validation = Joi23.object({
21403
+ page: Joi23.number().required(),
21404
+ limit: Joi23.number().required()
21405
+ });
21406
+ const { error } = validation.validate({ page, limit });
21407
+ if (error) {
21408
+ next(new BadRequestError41(error.message));
21409
+ }
21410
+ try {
21411
+ const promoCodes = _getPromoCodes({
21412
+ page: parseInt(page),
21413
+ limit: parseInt(limit),
21414
+ search,
21415
+ status
21416
+ });
21417
+ res.json(promoCodes);
21418
+ return;
21419
+ } catch (error2) {
21420
+ next(error2);
21421
+ }
21422
+ }
21423
+ return {
21424
+ add,
21425
+ getByCode,
21426
+ getPromoCodes
21427
+ };
21428
+ }
21429
+
21430
+ // src/controllers/order.controller.ts
21431
+ import { BadRequestError as BadRequestError42 } from "@goweekdays/utils";
21432
+ import Joi24 from "joi";
21433
+ function useOrderController() {
21434
+ const { getOrders: _getOrders } = useOrderRepo();
21435
+ async function getOrders(req, res, next) {
21436
+ const page = req.query.page ?? 1;
21437
+ const limit = req.query.limit ?? 10;
21438
+ const search = req.query.search ?? "";
21439
+ const status = req.query.status ?? "succeeded";
21440
+ const id = req.query.id ?? "";
21441
+ const validation = Joi24.object({
21442
+ page: Joi24.number().required(),
21443
+ limit: Joi24.number().required().min(10),
21444
+ search: Joi24.string().optional().allow("", null),
21445
+ status: Joi24.string().optional().allow("", null),
21446
+ id: Joi24.string().hex().optional().allow("", null)
21447
+ });
21448
+ const { error } = validation.validate({ page, limit, search, status, id });
21449
+ if (error) {
21450
+ next(new BadRequestError42(error.message));
21451
+ return;
21452
+ }
21453
+ try {
21454
+ const orders = await _getOrders({
21455
+ page: parseInt(page),
21456
+ limit: parseInt(limit),
21457
+ search,
21458
+ status,
21459
+ id
21460
+ });
21461
+ res.json(orders);
21462
+ return;
21463
+ } catch (error2) {
21464
+ next(error2);
21465
+ }
21466
+ }
21467
+ return {
21468
+ getOrders
21469
+ };
21470
+ }
20580
21471
  export {
20581
21472
  ACCESS_TOKEN_EXPIRY,
20582
21473
  ACCESS_TOKEN_SECRET,
@@ -20599,8 +21490,10 @@ export {
20599
21490
  MMember,
20600
21491
  MONGO_DB,
20601
21492
  MONGO_URI,
21493
+ MOrder,
20602
21494
  MOrg,
20603
21495
  MPaymentMethod,
21496
+ MPromoCode,
20604
21497
  MRole,
20605
21498
  MSubscription,
20606
21499
  MToken,
@@ -20628,6 +21521,7 @@ export {
20628
21521
  XENDIT_BASE_URL,
20629
21522
  XENDIT_SECRET_KEY,
20630
21523
  isDev,
21524
+ schema2 as schema,
20631
21525
  useAddressController,
20632
21526
  useAddressRepo,
20633
21527
  useAuthController,
@@ -20645,12 +21539,16 @@ export {
20645
21539
  useFileRepo,
20646
21540
  useFileService,
20647
21541
  useMemberRepo,
21542
+ useOrderController,
21543
+ useOrderRepo,
20648
21544
  useOrgController,
20649
21545
  useOrgRepo,
20650
21546
  useOrgService,
20651
21547
  usePaymentMethodController,
20652
21548
  usePaymentMethodRepo,
20653
21549
  usePaymentMethodService,
21550
+ usePromoCodeController,
21551
+ usePromoCodeRepo,
20654
21552
  useRoleController,
20655
21553
  useRoleRepo,
20656
21554
  useRoleService,