@7365admin1/core 3.48.1-staging.168 → 3.48.1-staging.169

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.
@@ -0,0 +1,21 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Scope the service provider billing routes to the organisation
6
+
7
+ `/api/provider-billings` carried `requireAuth` and nothing more on all five
8
+ handlers, and `service-provider-billing.controller.ts` held no authorization
9
+ identifier of any kind. A service provider billing record is what a contractor
10
+ invoices an organisation for, so any signed-in account on the platform could
11
+ read another organisation's invoices, swap the attachments that evidence one,
12
+ flip its status, add an acknowledgement that was never given, or delete it.
13
+
14
+ The scope here is the ORGANISATION, not the estate: every row carries `orgId`
15
+ and no `site`, so the rule is `requireOrgAccess` — Seven365 staff, or a live
16
+ member of that organisation — not `requireSiteReach`.
17
+
18
+ Adds `requireServiceProviderBillingReach`, plus an uncached
19
+ `getRawServiceProviderBillingById` so the check is not decided from a 15-minute
20
+ cache entry (the existing reader is cached and throws `NotFoundError`, which
21
+ would also answer before the guard ran).
package/dist/index.d.ts CHANGED
@@ -5438,6 +5438,7 @@ declare function useServiceProviderBillingRepo(): {
5438
5438
  pageRange: string;
5439
5439
  } | TServiceProviderBilling>;
5440
5440
  getSiteServiceProviderBillingById: (_id: string | ObjectId, session?: ClientSession) => Promise<mongodb.WithId<bson.Document> | TServiceProviderBilling>;
5441
+ getRawServiceProviderBillingById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
5441
5442
  updateServiceProviderBillingById: (_id: ObjectId | string, value: Partial<TServiceProviderBilling>, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
5442
5443
  deleteServiceProviderBillingById: (_id: string | ObjectId) => Promise<number>;
5443
5444
  createIndexes: () => Promise<void>;
@@ -5448,6 +5449,36 @@ declare function useServiceProviderBillingService(): {
5448
5449
  updateServiceProviderBillingById: (id: string | ObjectId, value: Partial<TServiceProviderBilling>) => Promise<string>;
5449
5450
  };
5450
5451
 
5452
+ /**
5453
+ * Who may see, or change, a service provider's billing records.
5454
+ *
5455
+ * A service provider billing record is what a contractor invoices an
5456
+ * organisation for - the amount, the period, the attachments that evidence it,
5457
+ * and the people who acknowledged it. It is money.
5458
+ *
5459
+ * All five routes on `/api/provider-billings` carried `requireAuth` and nothing
5460
+ * more, and this controller held no authorization identifier of any kind, so
5461
+ * being signed in ANYWHERE on the platform was enough to read another
5462
+ * organisation's invoices, restate one, replace its evidence, or delete it.
5463
+ *
5464
+ * The scope here is the ORGANISATION, not the estate. Every row carries
5465
+ * `orgId` and no `site` - `getAll` is asked for an `org`, and the repository
5466
+ * builds `{ orgId: org, status }`. So the rule is `requireOrgAccess`, the same
5467
+ * one `/api/customer-sites` and `/api/members` already use: Seven365 staff, or
5468
+ * a live member of that organisation. Using `requireSiteReach` here would be
5469
+ * asking the wrong question of the wrong field.
5470
+ *
5471
+ * - `POST /` already REQUIRES `orgId` in the body and `GET /` already REQUIRES
5472
+ * `org` in the query, so the guard checks the organisation the request
5473
+ * already names and no caller's contract changes.
5474
+ * - The three record routes name only a record, so the organisation is read
5475
+ * off the STORED row via `requireServiceProviderBillingReach`, and an
5476
+ * `orgId` in the caller's own body cannot stand in for it.
5477
+ *
5478
+ * `PUT /id/:id` cannot MOVE a record between organisations:
5479
+ * `schemaUpdateServiceProviderBilling` does not accept `orgId` at all, so there
5480
+ * is no destination to check.
5481
+ */
5451
5482
  declare function useServiceProviderBillingController(): {
5452
5483
  add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
5453
5484
  getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
package/dist/index.js CHANGED
@@ -54331,10 +54331,19 @@ function useServiceProviderBillingRepo() {
54331
54331
  throw error;
54332
54332
  }
54333
54333
  }
54334
+ async function getRawServiceProviderBillingById(_id) {
54335
+ try {
54336
+ _id = new import_mongodb98.ObjectId(_id);
54337
+ } catch (error) {
54338
+ throw new import_node_server_utils158.BadRequestError("Invalid service provider billing ID format.");
54339
+ }
54340
+ return await collection.findOne({ _id });
54341
+ }
54334
54342
  return {
54335
54343
  add,
54336
54344
  getAll,
54337
54345
  getSiteServiceProviderBillingById,
54346
+ getRawServiceProviderBillingById,
54338
54347
  updateServiceProviderBillingById,
54339
54348
  deleteServiceProviderBillingById,
54340
54349
  createIndexes
@@ -54393,8 +54402,13 @@ function useServiceProviderBillingController() {
54393
54402
  const {
54394
54403
  getAll: _getAll,
54395
54404
  getSiteServiceProviderBillingById: _getServiceProviderBillingById,
54405
+ getRawServiceProviderBillingById: _getRawServiceProviderBillingById,
54396
54406
  deleteServiceProviderBillingById: _deleteServiceProviderBillingById
54397
54407
  } = useServiceProviderBillingRepo();
54408
+ async function requireServiceProviderBillingReach(req, _id) {
54409
+ const row = await _getRawServiceProviderBillingById(_id);
54410
+ await requireOrgAccess(req, row?.orgId?.toString());
54411
+ }
54398
54412
  async function add(req, res, next) {
54399
54413
  const payload = { ...req.body };
54400
54414
  const { error } = schemaServiceProviderBilling.validate(payload, {
@@ -54407,6 +54421,7 @@ function useServiceProviderBillingController() {
54407
54421
  return;
54408
54422
  }
54409
54423
  try {
54424
+ await requireOrgAccess(req, payload.orgId);
54410
54425
  const data = await _add(payload);
54411
54426
  res.status(201).json(data);
54412
54427
  return;
@@ -54453,6 +54468,7 @@ function useServiceProviderBillingController() {
54453
54468
  }
54454
54469
  });
54455
54470
  try {
54471
+ await requireOrgAccess(req, org);
54456
54472
  const data = await _getAll({
54457
54473
  search,
54458
54474
  page,
@@ -54479,6 +54495,7 @@ function useServiceProviderBillingController() {
54479
54495
  return;
54480
54496
  }
54481
54497
  try {
54498
+ await requireServiceProviderBillingReach(req, _id);
54482
54499
  const data = await _getServiceProviderBillingById(_id);
54483
54500
  res.status(200).json(data);
54484
54501
  return;
@@ -54501,6 +54518,7 @@ function useServiceProviderBillingController() {
54501
54518
  return;
54502
54519
  }
54503
54520
  try {
54521
+ await requireServiceProviderBillingReach(req, _id);
54504
54522
  const result = await _updateServiceProviderBillingById(_id, req.body);
54505
54523
  res.status(200).json({ message: result });
54506
54524
  return;
@@ -54520,6 +54538,7 @@ function useServiceProviderBillingController() {
54520
54538
  return;
54521
54539
  }
54522
54540
  try {
54541
+ await requireServiceProviderBillingReach(req, _id);
54523
54542
  await _deleteServiceProviderBillingById(_id);
54524
54543
  res.status(200).json({ message: "Successfully deleted service provider billing." });
54525
54544
  return;