@7365admin1/core 3.41.0 → 3.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.42.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ff7b915: release changes in payment api
8
+
9
+ ## 3.41.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 8eb6601: Stop rejecting site names that only differ by their building number
14
+
15
+ Adding a site refused any name within a Levenshtein distance of 2 of an
16
+ existing site in the same organisation, and told the user to contact support.
17
+ That is exactly one character, so "Winsland House II" could not be added next
18
+ to "Winsland House I". The same rule blocked "Tower A" beside "Tower B",
19
+ "Phase 2" beside "Phase 1" and "Block 15" beside "Block 5" — the standard way
20
+ buildings are named here.
21
+
22
+ The check now treats trailing numbers, Roman numerals and single letters as the
23
+ part that tells two buildings apart: if they differ, the names are different
24
+ sites and the distance is never measured. Real duplicates are still refused —
25
+ an exact repeat, a different capitalisation, stray or doubled whitespace,
26
+ punctuation-only differences, and a one or two character typo within the same
27
+ building. "House 1" and "House I" are still read as the same building.
28
+
29
+ The refusal now names the site it matched and says what to do about it instead
30
+ of pointing the user at support.
31
+
32
+ `site.repo.getByExactName` also built its case-insensitive regex from the raw
33
+ name; a name containing regex characters either threw or matched a site it is
34
+ not. It is escaped.
35
+
3
36
  ## 3.41.0
4
37
 
5
38
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -6907,6 +6907,9 @@ declare function useRedDotPaymentController(): {
6907
6907
  redirectPaymentTransaction: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
6908
6908
  enquirePaymentTransaction: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
6909
6909
  createPayment: (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
6910
+ getPaymentByReference: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6911
+ updateStatus: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6912
+ getPaidBills: (req: Request, res: Response, next: NextFunction) => Promise<void>;
6910
6913
  };
6911
6914
 
6912
6915
  interface IDirectPayment extends IBaseModel {
@@ -6945,6 +6948,8 @@ declare const useRedDotPaymentSvc: () => {
6945
6948
  type TBillingItems = {
6946
6949
  _id: ObjectId | string;
6947
6950
  name: string;
6951
+ amount: number;
6952
+ referenceNumber: string;
6948
6953
  };
6949
6954
  type TBillingPayments = {
6950
6955
  _id?: ObjectId;
@@ -6967,11 +6972,27 @@ type TBillingPayments = {
6967
6972
 
6968
6973
  declare const useRedDotPaymentRepo: () => {
6969
6974
  paySingleUnitBill: (refId: string, payload: Partial<TUnitBilling>) => Promise<mongodb.WithId<bson.Document> | null>;
6970
- createPayment: (type: string, payload: Partial<TBillingPayments>, session?: ClientSession) => Promise<ObjectId | undefined>;
6975
+ createPayment: (type: string, payload: Partial<TBillingPayments>, session?: ClientSession) => Promise<string | undefined>;
6971
6976
  payMultipleUnitBill: (refId: string[], payload: Partial<TUnitBilling>) => Promise<{
6972
6977
  message: string;
6973
6978
  remainingBalance: number;
6974
6979
  }>;
6980
+ getPaidBills: ({ search, page, limit, sort, month, year, unitId, }: {
6981
+ search?: string | undefined;
6982
+ page?: number | undefined;
6983
+ limit?: number | undefined;
6984
+ sort?: Record<string, any> | undefined;
6985
+ month?: string | undefined;
6986
+ year?: string | undefined;
6987
+ unitId: string | ObjectId;
6988
+ }, session?: ClientSession) => Promise<{
6989
+ items: any[];
6990
+ pages: number;
6991
+ pageRange: string;
6992
+ }>;
6993
+ createIndexes: () => Promise<void>;
6994
+ getPaymentByReference: (referenceNumber: string, session?: ClientSession) => Promise<TBillingPayments>;
6995
+ updateStatus: (referenceNumber: string, status: string, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
6975
6996
  };
6976
6997
 
6977
6998
  declare enum VerificationType {
package/dist/index.js CHANGED
@@ -536,13 +536,13 @@ var require_logger = __commonJS({
536
536
  "use strict";
537
537
  exports.__esModule = true;
538
538
  var _utils = require_utils();
539
- var logger201 = {
539
+ var logger202 = {
540
540
  methodMap: ["debug", "info", "warn", "error"],
541
541
  level: "info",
542
542
  // Maps a given level value to the `methodMap` indexes above.
543
543
  lookupLevel: function lookupLevel(level) {
544
544
  if (typeof level === "string") {
545
- var levelMap = _utils.indexOf(logger201.methodMap, level.toLowerCase());
545
+ var levelMap = _utils.indexOf(logger202.methodMap, level.toLowerCase());
546
546
  if (levelMap >= 0) {
547
547
  level = levelMap;
548
548
  } else {
@@ -553,9 +553,9 @@ var require_logger = __commonJS({
553
553
  },
554
554
  // Can be overridden in the host environment
555
555
  log: function log(level) {
556
- level = logger201.lookupLevel(level);
557
- if (typeof console !== "undefined" && logger201.lookupLevel(logger201.level) <= level) {
558
- var method = logger201.methodMap[level];
556
+ level = logger202.lookupLevel(level);
557
+ if (typeof console !== "undefined" && logger202.lookupLevel(logger202.level) <= level) {
558
+ var method = logger202.methodMap[level];
559
559
  if (!console[method]) {
560
560
  method = "log";
561
561
  }
@@ -566,7 +566,7 @@ var require_logger = __commonJS({
566
566
  }
567
567
  }
568
568
  };
569
- exports["default"] = logger201;
569
+ exports["default"] = logger202;
570
570
  module2.exports = exports["default"];
571
571
  }
572
572
  });
@@ -11666,8 +11666,9 @@ function useSiteRepo() {
11666
11666
  } catch (error2) {
11667
11667
  throw new import_node_server_utils19.BadRequestError("Invalid org ID format.");
11668
11668
  }
11669
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11669
11670
  const query = {
11670
- name: { $regex: new RegExp(`^${name}$`, "i") },
11671
+ name: { $regex: new RegExp(`^${escapedName}$`, "i") },
11671
11672
  // Case-insensitive exact match
11672
11673
  orgId,
11673
11674
  status: { $ne: "deleted" }
@@ -32537,7 +32538,57 @@ function useCustomerSiteRepo() {
32537
32538
 
32538
32539
  // src/services/customer-site.service.ts
32539
32540
  var import_node_server_utils96 = require("@7365admin1/node-server-utils");
32541
+
32542
+ // src/utils/site-name.util.ts
32540
32543
  var import_fast_levenshtein = __toESM(require("fast-levenshtein"));
32544
+ var ROMAN = /^(?=[ivx])(x{0,3})(ix|iv|v?i{0,3})$/;
32545
+ var ROMAN_VALUE = { i: 1, v: 5, x: 10 };
32546
+ function normalizeSiteName(name) {
32547
+ return String(name ?? "").normalize("NFKC").toLowerCase().replace(/[‘’']/g, "").replace(/[^a-z0-9]+/g, " ").trim();
32548
+ }
32549
+ function romanToNumber(token) {
32550
+ let total = 0;
32551
+ for (let i = 0; i < token.length; i++) {
32552
+ const value = ROMAN_VALUE[token[i]];
32553
+ const next = ROMAN_VALUE[token[i + 1]];
32554
+ total += next && next > value ? -value : value;
32555
+ }
32556
+ return total;
32557
+ }
32558
+ function distinguishingTokens(normalized) {
32559
+ if (!normalized)
32560
+ return [];
32561
+ return normalized.split(" ").filter((t) => /^\d+$/.test(t) || ROMAN.test(t) || /^[a-z]$/.test(t)).map((t) => ROMAN.test(t) ? String(romanToNumber(t)) : t);
32562
+ }
32563
+ function matchSiteName(candidate, existing) {
32564
+ const a = normalizeSiteName(candidate);
32565
+ const b = normalizeSiteName(existing);
32566
+ if (!a || !b)
32567
+ return null;
32568
+ if (a === b)
32569
+ return "duplicate";
32570
+ const tokensA = distinguishingTokens(a).join(" ");
32571
+ const tokensB = distinguishingTokens(b).join(" ");
32572
+ if (tokensA !== tokensB)
32573
+ return null;
32574
+ return import_fast_levenshtein.default.get(a, b) <= 2 ? "near-duplicate" : null;
32575
+ }
32576
+ function findSiteNameClash(candidate, existingNames) {
32577
+ for (const name of existingNames) {
32578
+ const match = matchSiteName(candidate, name);
32579
+ if (match)
32580
+ return { name, match };
32581
+ }
32582
+ return null;
32583
+ }
32584
+ function siteNameClashMessage(existingName, match) {
32585
+ if (match === "duplicate") {
32586
+ return `A site called "${existingName}" already exists in this organisation. Give the new site a different name, or edit "${existingName}" instead.`;
32587
+ }
32588
+ return `This name is within a character or two of "${existingName}", which already exists in this organisation. If it is the same property, edit "${existingName}" instead. If it is a different one, include what tells them apart \u2014 the block, tower, phase, or number \u2014 and save again.`;
32589
+ }
32590
+
32591
+ // src/services/customer-site.service.ts
32541
32592
  function useCustomerSiteService() {
32542
32593
  const { add: _add, updateCustomerSiteById, getById: _getById } = useCustomerSiteRepo();
32543
32594
  const {
@@ -32559,20 +32610,18 @@ function useCustomerSiteService() {
32559
32610
  const exactMatches = await getSiteByExactName(value.name, value.siteOrg);
32560
32611
  if (exactMatches && exactMatches.length > 0) {
32561
32612
  throw new import_node_server_utils96.BadRequestError(
32562
- "Site with this name already exists in the organization."
32613
+ siteNameClashMessage(exactMatches[0].name, "duplicate")
32563
32614
  );
32564
32615
  }
32565
- const threshold = 2;
32566
32616
  const sites = await getSiteByName(value.name);
32567
- if (sites && sites.length > 0) {
32568
- const similar = sites.filter((doc) => {
32569
- return doc.orgId && doc.name && doc.orgId.toString() === value.siteOrg.toString() && import_fast_levenshtein.default.get(value.name.toLowerCase(), doc.name.toLowerCase()) <= threshold;
32570
- });
32571
- if (similar.length > 0) {
32572
- throw new import_node_server_utils96.BadRequestError(
32573
- "Failed to add site, site with closely similar name found. Please contact seven365 support."
32574
- );
32575
- }
32617
+ const candidates = (sites ?? []).filter(
32618
+ (doc) => doc.orgId && doc.name && doc.orgId.toString() === value.siteOrg.toString()
32619
+ ).map((doc) => doc.name);
32620
+ const clash = findSiteNameClash(value.name, candidates);
32621
+ if (clash) {
32622
+ throw new import_node_server_utils96.BadRequestError(
32623
+ siteNameClashMessage(clash.name, clash.match)
32624
+ );
32576
32625
  }
32577
32626
  const siteId = await createSite(
32578
32627
  {
@@ -64835,9 +64884,19 @@ var import_mongodb135 = require("mongodb");
64835
64884
  var import_node_server_utils223 = require("@7365admin1/node-server-utils");
64836
64885
  var import_mongodb134 = require("mongodb");
64837
64886
  var import_joi126 = __toESM(require("joi"));
64887
+ var BillingPaymentStatus = /* @__PURE__ */ ((BillingPaymentStatus2) => {
64888
+ BillingPaymentStatus2["PENDING"] = "pending";
64889
+ BillingPaymentStatus2["SUCCESS"] = "success";
64890
+ BillingPaymentStatus2["FAILED"] = "failed";
64891
+ BillingPaymentStatus2["PARTIAL"] = "partial";
64892
+ BillingPaymentStatus2["CANCELLED"] = "cancelled";
64893
+ return BillingPaymentStatus2;
64894
+ })(BillingPaymentStatus || {});
64838
64895
  var schemaBillingItems = import_joi126.default.object({
64839
64896
  _id: import_joi126.default.string().hex().optional(),
64840
- name: import_joi126.default.string().optional().allow(null, "")
64897
+ name: import_joi126.default.string().optional().allow(null, ""),
64898
+ amount: import_joi126.default.number().optional().allow(null, ""),
64899
+ referenceNumber: import_joi126.default.string().optional().allow(null, "")
64841
64900
  });
64842
64901
  var schemaBillingPayments = import_joi126.default.object({
64843
64902
  _id: import_joi126.default.string().hex().optional(),
@@ -64944,12 +65003,60 @@ var useRedDotPaymentRepo = () => {
64944
65003
  const redDotMerchantCollection = () => {
64945
65004
  return getDB2().collection("payment-gateways");
64946
65005
  };
65006
+ async function createIndexes() {
65007
+ try {
65008
+ await paymentCollection().createIndexes([
65009
+ // A referenceNumber-prefixed compound index serves both the lookup by
65010
+ // reference alone and the { referenceNumber, status } lookups used by
65011
+ // the pay single / pay multiple flows.
65012
+ {
65013
+ key: { referenceNumber: 1, status: 1 },
65014
+ name: "referenceNumber_1_status_1"
65015
+ }
65016
+ ]);
65017
+ } catch (error) {
65018
+ import_node_server_utils224.logger.log({
65019
+ level: "error",
65020
+ message: error.message
65021
+ });
65022
+ throw new import_node_server_utils224.InternalServerError(
65023
+ "Failed to create index on billing payments."
65024
+ );
65025
+ }
65026
+ }
65027
+ async function getPaymentByReference(referenceNumber, session) {
65028
+ const reference = typeof referenceNumber === "string" ? referenceNumber.trim() : "";
65029
+ if (!reference) {
65030
+ throw new import_node_server_utils224.BadRequestError("Reference number is required.");
65031
+ }
65032
+ try {
65033
+ const payment = await paymentCollection().findOne(
65034
+ {
65035
+ referenceNumber: reference
65036
+ },
65037
+ { session }
65038
+ );
65039
+ if (!payment) {
65040
+ throw new import_node_server_utils224.NotFoundError("Payment not found.");
65041
+ }
65042
+ return payment;
65043
+ } catch (error) {
65044
+ if (error instanceof import_node_server_utils224.AppError) {
65045
+ throw error;
65046
+ }
65047
+ import_node_server_utils224.logger.log({
65048
+ level: "error",
65049
+ message: error.message
65050
+ });
65051
+ throw new import_node_server_utils224.InternalServerError("Failed to get payment.");
65052
+ }
65053
+ }
64947
65054
  async function createPayment(type, payload, session) {
64948
65055
  if (type == "single") {
64949
65056
  try {
64950
65057
  payload = MBillingItems(payload);
64951
- const res = await paymentCollection().insertOne(payload, { session });
64952
- return res.insertedId;
65058
+ await paymentCollection().insertOne(payload, { session });
65059
+ return payload.referenceNumber;
64953
65060
  } catch (error) {
64954
65061
  import_node_server_utils224.logger.log({
64955
65062
  level: "error",
@@ -64978,7 +65085,7 @@ var useRedDotPaymentRepo = () => {
64978
65085
  { $set: { referenceNumber } },
64979
65086
  { session }
64980
65087
  );
64981
- return res.insertedId;
65088
+ return referenceNumber;
64982
65089
  } catch (error) {
64983
65090
  import_node_server_utils224.logger.log({
64984
65091
  level: "error",
@@ -64996,6 +65103,76 @@ var useRedDotPaymentRepo = () => {
64996
65103
  }
64997
65104
  }
64998
65105
  }
65106
+ async function getPaidBills({
65107
+ search = "",
65108
+ page = 1,
65109
+ limit = 10,
65110
+ sort = {},
65111
+ month,
65112
+ year,
65113
+ unitId
65114
+ }, session) {
65115
+ let _unitId;
65116
+ try {
65117
+ _unitId = new import_mongodb135.ObjectId(unitId);
65118
+ } catch {
65119
+ throw new import_node_server_utils224.BadRequestError("Invalid unit ID format.");
65120
+ }
65121
+ page = page > 0 ? page - 1 : 0;
65122
+ let dateExpr = {};
65123
+ const datePaidRange = buildDatePaidRange(month, year);
65124
+ if (datePaidRange) {
65125
+ dateExpr.datePaid = datePaidRange;
65126
+ }
65127
+ const query = {
65128
+ unitId: _unitId,
65129
+ status: "success",
65130
+ ...search && {
65131
+ $or: [
65132
+ { referenceNumber: { $regex: search, $options: "i" } },
65133
+ { unitOwner: { $regex: search, $options: "i" } },
65134
+ { method: { $regex: search, $options: "i" } },
65135
+ { transaction_id: { $regex: search, $options: "i" } },
65136
+ { "unitBillingItems.name": { $regex: search, $options: "i" } },
65137
+ {
65138
+ $expr: {
65139
+ $regexMatch: {
65140
+ input: { $toString: "$totalAmount" },
65141
+ regex: search,
65142
+ options: "i"
65143
+ }
65144
+ }
65145
+ }
65146
+ ]
65147
+ },
65148
+ ...dateExpr
65149
+ };
65150
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
65151
+ try {
65152
+ const basePipeline = [
65153
+ { $match: query },
65154
+ { $sort: sort },
65155
+ { $skip: page * limit },
65156
+ { $limit: limit }
65157
+ ];
65158
+ const [items, countResult] = await Promise.all([
65159
+ paymentCollection().aggregate(basePipeline, { session }).toArray(),
65160
+ paymentCollection().aggregate([{ $match: query }, { $count: "total" }], { session }).toArray()
65161
+ ]);
65162
+ const totalCount = countResult[0]?.total || 0;
65163
+ const data = (0, import_node_server_utils224.paginate)(items, page, limit, totalCount);
65164
+ return data;
65165
+ } catch (error) {
65166
+ if (error instanceof import_node_server_utils224.AppError) {
65167
+ throw error;
65168
+ }
65169
+ import_node_server_utils224.logger.log({
65170
+ level: "error",
65171
+ message: error.message
65172
+ });
65173
+ throw new import_node_server_utils224.InternalServerError("Failed to retrieve paid bills.");
65174
+ }
65175
+ }
64999
65176
  async function paySingleUnitBill(refId, payload) {
65000
65177
  const session = import_node_server_utils224.useAtlas.getClient()?.startSession();
65001
65178
  try {
@@ -65158,6 +65335,52 @@ var useRedDotPaymentRepo = () => {
65158
65335
  session?.endSession();
65159
65336
  }
65160
65337
  }
65338
+ function buildDatePaidRange(month, year) {
65339
+ if (!year)
65340
+ return null;
65341
+ const yearNum = Number(year);
65342
+ if (!Number.isInteger(yearNum) || yearNum < 1970 || yearNum > 9999) {
65343
+ throw new import_node_server_utils224.BadRequestError("Invalid year filter.");
65344
+ }
65345
+ if (month) {
65346
+ const monthNum = Number(month);
65347
+ if (!Number.isInteger(monthNum) || monthNum < 1 || monthNum > 12) {
65348
+ throw new import_node_server_utils224.BadRequestError("Invalid month filter.");
65349
+ }
65350
+ return {
65351
+ $gte: new Date(yearNum, monthNum - 1, 1),
65352
+ $lt: new Date(yearNum, monthNum, 1)
65353
+ };
65354
+ }
65355
+ return {
65356
+ $gte: new Date(yearNum, 0, 1),
65357
+ $lt: new Date(yearNum + 1, 0, 1)
65358
+ };
65359
+ }
65360
+ async function updateStatus(referenceNumber, status, session) {
65361
+ const reference = typeof referenceNumber === "string" ? referenceNumber.trim() : "";
65362
+ if (!reference) {
65363
+ throw new import_node_server_utils224.BadRequestError("Reference number is required.");
65364
+ }
65365
+ try {
65366
+ const res = await paymentCollection().updateOne(
65367
+ { referenceNumber: reference, status: "pending" },
65368
+ { $set: { status, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
65369
+ { session }
65370
+ );
65371
+ if (res.matchedCount === 0) {
65372
+ throw new import_node_server_utils224.NotFoundError(
65373
+ "Payment not found or is no longer pending."
65374
+ );
65375
+ }
65376
+ return res;
65377
+ } catch (error) {
65378
+ if (error instanceof import_node_server_utils224.AppError) {
65379
+ throw error;
65380
+ }
65381
+ throw new import_node_server_utils224.InternalServerError("Failed to update payment status.");
65382
+ }
65383
+ }
65161
65384
  function formatDateString(today) {
65162
65385
  today = typeof today === "string" ? new Date(today) : today;
65163
65386
  let month = today.getMonth() + 1;
@@ -65166,7 +65389,15 @@ var useRedDotPaymentRepo = () => {
65166
65389
  const formattedDate = `${month.toString().padStart(2, "0")}${day.toString().padStart(2, "0")}${year}`;
65167
65390
  return formattedDate;
65168
65391
  }
65169
- return { paySingleUnitBill, createPayment, payMultipleUnitBill };
65392
+ return {
65393
+ paySingleUnitBill,
65394
+ createPayment,
65395
+ payMultipleUnitBill,
65396
+ getPaidBills,
65397
+ createIndexes,
65398
+ getPaymentByReference,
65399
+ updateStatus
65400
+ };
65170
65401
  };
65171
65402
 
65172
65403
  // src/services/reddot-payment.service.ts
@@ -65276,7 +65507,7 @@ var useRedDotPaymentSvc = () => {
65276
65507
  const success = {
65277
65508
  ...basePayload,
65278
65509
  paymentStatus: "paid" /* PAID */,
65279
- amountPaid: parseInt(amount)
65510
+ amountPaid: Number(amount)
65280
65511
  };
65281
65512
  if (isBulk) {
65282
65513
  await payMultipleUnitBill(refId, success);
@@ -65310,7 +65541,12 @@ var useRedDotPaymentSvc = () => {
65310
65541
  var import_joi127 = __toESM(require("joi"));
65311
65542
  var import_node_server_utils226 = require("@7365admin1/node-server-utils");
65312
65543
  function useRedDotPaymentController() {
65313
- const { createPayment: _createPayment } = useRedDotPaymentRepo();
65544
+ const {
65545
+ createPayment: _createPayment,
65546
+ updateStatus: _updateStatus,
65547
+ getPaymentByReference: _getPaymentByReference,
65548
+ getPaidBills: _getPaidBills
65549
+ } = useRedDotPaymentRepo();
65314
65550
  const redirectPaymentTransaction = async (req, res) => {
65315
65551
  try {
65316
65552
  const data = req.body;
@@ -65374,17 +65610,86 @@ function useRedDotPaymentController() {
65374
65610
  try {
65375
65611
  const payment = await _createPayment(type, value);
65376
65612
  res.status(201).json({
65377
- message: "Payment created successfully.",
65613
+ message: "success",
65378
65614
  data: payment
65379
65615
  });
65380
65616
  } catch (error) {
65381
- next(error);
65617
+ const status = error?.statusCode ?? 500;
65618
+ res.status(status).json({ message: "failed" });
65619
+ }
65620
+ }
65621
+ async function updateStatus(req, res, next) {
65622
+ const schema2 = import_joi127.default.object({
65623
+ referenceNumber: import_joi127.default.string().required(),
65624
+ status: import_joi127.default.string().valid(...Object.values(BillingPaymentStatus)).required()
65625
+ });
65626
+ const { error, value } = schema2.validate({
65627
+ referenceNumber: req.params.id,
65628
+ status: req.body.status
65629
+ });
65630
+ if (error) {
65631
+ import_node_server_utils226.logger.log({ level: "error", message: error.message });
65632
+ next(new import_node_server_utils226.BadRequestError(error.message));
65633
+ return;
65634
+ }
65635
+ try {
65636
+ const data = await _updateStatus(value.referenceNumber, value.status);
65637
+ res.status(200).json({ message: "success", data });
65638
+ return;
65639
+ } catch (error2) {
65640
+ import_node_server_utils226.logger.log({ level: "error", message: error2.message });
65641
+ next(error2);
65642
+ return;
65643
+ }
65644
+ }
65645
+ async function getPaymentByReference(req, res, next) {
65646
+ const schema2 = import_joi127.default.object({
65647
+ referenceNumber: import_joi127.default.string().required()
65648
+ });
65649
+ const { error, value } = schema2.validate(req.params);
65650
+ if (error) {
65651
+ next(new import_node_server_utils226.BadRequestError(error.message));
65652
+ return;
65653
+ }
65654
+ try {
65655
+ const payment = await _getPaymentByReference(value.referenceNumber);
65656
+ res.json({ data: payment });
65657
+ return;
65658
+ } catch (error2) {
65659
+ next(error2);
65660
+ return;
65661
+ }
65662
+ }
65663
+ async function getPaidBills(req, res, next) {
65664
+ const schema2 = import_joi127.default.object({
65665
+ unitId: import_joi127.default.string().hex().length(24).required(),
65666
+ page: import_joi127.default.number().integer().min(1).default(1),
65667
+ limit: import_joi127.default.number().integer().min(1).max(100).default(10),
65668
+ search: import_joi127.default.string().trim().allow("").default(""),
65669
+ month: import_joi127.default.string().pattern(/^(0?[1-9]|1[0-2])$/).allow("").optional(),
65670
+ year: import_joi127.default.string().pattern(/^\d{4}$/).allow("").optional()
65671
+ });
65672
+ const { error, value } = schema2.validate({ ...req.params, ...req.query });
65673
+ if (error) {
65674
+ next(new import_node_server_utils226.BadRequestError(error.message));
65675
+ return;
65676
+ }
65677
+ try {
65678
+ const bills = await _getPaidBills(value);
65679
+ res.json({ data: bills });
65680
+ return;
65681
+ } catch (error2) {
65682
+ next(error2);
65683
+ return;
65382
65684
  }
65383
65685
  }
65384
65686
  return {
65385
65687
  redirectPaymentTransaction,
65386
65688
  enquirePaymentTransaction,
65387
- createPayment
65689
+ createPayment,
65690
+ getPaymentByReference,
65691
+ updateStatus,
65692
+ getPaidBills
65388
65693
  };
65389
65694
  }
65390
65695