@7365admin1/core 3.48.1-staging.169 → 3.48.1-staging.171
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/.changeset/site-soa-scope.md +30 -0
- package/.changeset/site-unit-billing-scope.md +25 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +2040 -1975
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +638 -573
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +50 -0
- package/test/e2e/site-soa-scope.e2e.test.mjs +548 -0
- package/test/e2e/site-unit-billing-scope.e2e.test.mjs +442 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the statement of account routes to the estate and the unit, and take the requester and approver from the session
|
|
6
|
+
|
|
7
|
+
Eight of the nine routes on `/api/site-soa` carried `requireAuth` and nothing
|
|
8
|
+
more, and `site-soa.controller.ts` held no authorization identifier of any kind.
|
|
9
|
+
A statement of account is one unit's ledger for a period, so any signed-in
|
|
10
|
+
account on the platform could read another estate's statements, restate one,
|
|
11
|
+
approve or reject it, move it to another estate, or delete it.
|
|
12
|
+
|
|
13
|
+
`GET /user` is named for the signed-in resident but took `site` and `unitId`
|
|
14
|
+
from the query and identified the caller not at all, so a resident could read a
|
|
15
|
+
neighbour's statement of account by changing one id in a URL. It now requires
|
|
16
|
+
`unitId` and checks it against a live `people` row joining the caller to that
|
|
17
|
+
unit, via `requireOwnUnit`.
|
|
18
|
+
|
|
19
|
+
`add` set `createdBy`, and `reviewSOA` set `approvedBy._id`, by parsing the raw
|
|
20
|
+
`user` cookie off the request, so a statement could be requested under another
|
|
21
|
+
resident's name and approved under another person's. Both now come from
|
|
22
|
+
`callerId(req)`.
|
|
23
|
+
|
|
24
|
+
Adds `requireStatementReach` plus an uncached `getRawStatementOfAccountById`.
|
|
25
|
+
`PUT /id/:id` checks both ends, because `schemaUpdateStatementOfAccount` accepts
|
|
26
|
+
`site` and `updateById` writes it.
|
|
27
|
+
|
|
28
|
+
`GET /generate-pdf` is deliberately unchanged: it is the platform's PDF service,
|
|
29
|
+
called from every web app by `@7365admin1/layer-common`'s `usePDFDownload`, and
|
|
30
|
+
it is authorized by forwarding the caller's own session to the headless browser.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the unit billing routes to the estate, and the resident routes to the caller's own unit
|
|
6
|
+
|
|
7
|
+
`/api/site-unit-billing` carried `requireAuth` and nothing more on all seven
|
|
8
|
+
handlers, and `site-unit-billing.controller.ts` held no authorization identifier
|
|
9
|
+
of any kind. Two separate problems followed.
|
|
10
|
+
|
|
11
|
+
On the estate side, any signed-in account could add a bill to any estate, read
|
|
12
|
+
another estate's whole billing run, restate what a resident owes, move a bill to
|
|
13
|
+
another estate, or delete it. Those five routes now use `requireSiteReach`, plus
|
|
14
|
+
a new `requireUnitBillingReach` on the stored row and an uncached
|
|
15
|
+
`getRawUnitBillingById`. `PUT /id/:id` checks both ends, because
|
|
16
|
+
`schemaUpdateSiteUnitBilling` accepts `site` and `updateById` writes it.
|
|
17
|
+
|
|
18
|
+
On the resident side, `GET /user` and `GET /user/unsettled` are named for the
|
|
19
|
+
signed-in resident but took `site` and `unitId` from the QUERY and identified the
|
|
20
|
+
caller not at all, so they were never "my bills" — they were any unit's bills at
|
|
21
|
+
any estate. A resident passing a neighbour's unit id got the neighbour's
|
|
22
|
+
maintenance bills, and omitting `unitId` dropped that filter too and returned the
|
|
23
|
+
whole estate's. Both routes now require `unitId` and check it against a live
|
|
24
|
+
`people` row joining the caller to that unit at that site, via a new
|
|
25
|
+
`requireOwnUnit`. Seven365 platform staff are exempt.
|
package/dist/index.d.ts
CHANGED
|
@@ -6258,6 +6258,7 @@ declare function useSiteUnitBillingRepo(): {
|
|
|
6258
6258
|
dateTo?: string | undefined;
|
|
6259
6259
|
}, session?: ClientSession) => Promise<{}>;
|
|
6260
6260
|
getById: (_id: string | ObjectId) => Promise<TUnitBilling | null>;
|
|
6261
|
+
getRawUnitBillingById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
6261
6262
|
updateById: (_id: string | ObjectId, value: Partial<TUnitBilling>, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
6262
6263
|
deleteById: (_id: string | ObjectId) => Promise<number>;
|
|
6263
6264
|
getUnitBillingBySite: ({ status, site, dateFrom, dateTo, unitId, }: {
|
|
@@ -6307,6 +6308,39 @@ declare function useSiteUnitBillingService(): {
|
|
|
6307
6308
|
checkOverDueBills: () => Promise<"No overdue bills found." | "Successfully checked and updated overdue bills.">;
|
|
6308
6309
|
};
|
|
6309
6310
|
|
|
6311
|
+
/**
|
|
6312
|
+
* Who may see, or change, a unit's maintenance bills.
|
|
6313
|
+
*
|
|
6314
|
+
* A site unit billing row is one unit's bill for a period - the amount, what is
|
|
6315
|
+
* outstanding, what has been paid, and against which billing item. It is money,
|
|
6316
|
+
* and on the resident side it is somebody's household finances.
|
|
6317
|
+
*
|
|
6318
|
+
* All seven routes on `/api/site-unit-billing` carried `requireAuth` and
|
|
6319
|
+
* nothing more, and this controller held no authorization identifier of any
|
|
6320
|
+
* kind, so being signed in ANYWHERE on the platform was enough to read another
|
|
6321
|
+
* estate's billing run, restate a bill, move it to another estate, or delete
|
|
6322
|
+
* it.
|
|
6323
|
+
*
|
|
6324
|
+
* The two resident routes are the sharp ones and are guarded differently from
|
|
6325
|
+
* the rest - see `requireOwnUnit`. `GET /user` and `GET /user/unsettled` are
|
|
6326
|
+
* named for the signed-in resident but took `site` and `unitId` from the QUERY
|
|
6327
|
+
* and identified the caller not at all, so they were never "my bills": they
|
|
6328
|
+
* were "any unit's bills, at any estate". A resident passing a NEIGHBOUR's unit
|
|
6329
|
+
* id got the neighbour's maintenance bills, and omitting `unitId` dropped that
|
|
6330
|
+
* filter as well.
|
|
6331
|
+
*
|
|
6332
|
+
* For the five estate-side routes the scope is the estate, and `requireSiteReach`
|
|
6333
|
+
* is the rule `/api/patrol-logs`, `/api/feedbacks`, `/api/work-orders` and
|
|
6334
|
+
* `/api/occurrence-books` already use.
|
|
6335
|
+
*
|
|
6336
|
+
* - `POST /` and `GET /` name a site, so the guard checks the site the request
|
|
6337
|
+
* already names.
|
|
6338
|
+
* - The three record routes name only a record, so the site is read off the
|
|
6339
|
+
* STORED row via `requireUnitBillingReach`.
|
|
6340
|
+
*
|
|
6341
|
+
* `PUT /id/:id` CAN move a bill: `schemaUpdateSiteUnitBilling` accepts `site`
|
|
6342
|
+
* and `updateById` writes it, so both ends are checked.
|
|
6343
|
+
*/
|
|
6310
6344
|
declare function useSiteUnitBillingController(): {
|
|
6311
6345
|
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
6312
6346
|
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -7170,6 +7204,7 @@ declare function useStatementOfAccountRepo(): {
|
|
|
7170
7204
|
dateTo?: string | undefined;
|
|
7171
7205
|
}, session?: ClientSession) => Promise<{}>;
|
|
7172
7206
|
getById: (_id: string | ObjectId) => Promise<TStatementOfAccount | null>;
|
|
7207
|
+
getRawStatementOfAccountById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
7173
7208
|
updateById: (_id: string | ObjectId, value: Partial<TStatementOfAccount>, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
7174
7209
|
deleteById: (_id: string | ObjectId) => Promise<number>;
|
|
7175
7210
|
updateStatusById: (_id: string | ObjectId, value: Pick<TStatementOfAccount, "status">, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
@@ -7193,6 +7228,43 @@ declare function useStatementOfAccountRepo(): {
|
|
|
7193
7228
|
createIndexes: () => Promise<string>;
|
|
7194
7229
|
};
|
|
7195
7230
|
|
|
7231
|
+
/**
|
|
7232
|
+
* Who may see, or change, a statement of account.
|
|
7233
|
+
*
|
|
7234
|
+
* A statement of account is one unit's ledger for a period - every charge and
|
|
7235
|
+
* every payment on a household's account, requested by the resident and
|
|
7236
|
+
* approved by the estate. It is money, and on the resident side it is somebody
|
|
7237
|
+
* else's household finances.
|
|
7238
|
+
*
|
|
7239
|
+
* Eight of the nine routes on `/api/site-soa` carried `requireAuth` and nothing
|
|
7240
|
+
* more, and this controller held no authorization identifier of any kind, so
|
|
7241
|
+
* being signed in ANYWHERE on the platform was enough to read another estate's
|
|
7242
|
+
* statements, restate one, approve or reject it, move it to another estate, or
|
|
7243
|
+
* delete it.
|
|
7244
|
+
*
|
|
7245
|
+
* Three distinct problems, and they need three different answers.
|
|
7246
|
+
*
|
|
7247
|
+
* 1. THE ESTATE SIDE. `POST /` and `GET /` name a site, so the guard checks the
|
|
7248
|
+
* site the request already names. The four record routes name only a record,
|
|
7249
|
+
* so the site is read off the STORED row via `requireStatementReach`, and a
|
|
7250
|
+
* `site` in the caller's own body cannot stand in for it. `PUT /id/:id` CAN
|
|
7251
|
+
* move a statement - `schemaUpdateStatementOfAccount` accepts `site` and
|
|
7252
|
+
* `updateById` writes it - so both ends are checked.
|
|
7253
|
+
*
|
|
7254
|
+
* 2. THE RESIDENT SIDE. `GET /user` is named for the signed-in resident but
|
|
7255
|
+
* took `site` and `unitId` from the QUERY and identified the caller not at
|
|
7256
|
+
* all, so it was never "my statements": it was any unit's, at any estate.
|
|
7257
|
+
* `requireOwnUnit` asks the question the data already answers - is there a
|
|
7258
|
+
* live `people` row joining this caller to this unit at this site?
|
|
7259
|
+
*
|
|
7260
|
+
* 3. IDENTITY FROM THE REQUEST. `add` set `createdBy` and `reviewSOA` set
|
|
7261
|
+
* `approvedBy._id` by parsing the raw `user` COOKIE off the request, so a
|
|
7262
|
+
* statement could be requested under another resident's name and, worse,
|
|
7263
|
+
* APPROVED under another person's. Both now come from `callerId(req)`.
|
|
7264
|
+
*
|
|
7265
|
+
* `GET /generate-pdf` is deliberately NOT scoped here - see the note on the
|
|
7266
|
+
* handler.
|
|
7267
|
+
*/
|
|
7196
7268
|
declare function useStatementOfAccountController(): {
|
|
7197
7269
|
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
7198
7270
|
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|