@happyvertical/smrt-support 0.40.70 → 0.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/AGENTS.md CHANGED
@@ -238,10 +238,43 @@ by #1955. No inter-`smrt-*` `peerDependencies`.
238
238
 
239
239
  ```sh
240
240
  pnpm --filter @happyvertical/smrt-support test
241
+ pnpm --filter @happyvertical/smrt-support test:postgres
241
242
  pnpm --filter @happyvertical/smrt-support typecheck
242
243
  pnpm --filter @happyvertical/smrt-support build
243
244
  ```
244
245
 
246
+ `test:postgres` is the lane that holds the money/rate line — SQLite's type
247
+ affinity stores a REAL in an INTEGER column without complaint, so a money field
248
+ that reverted to DECIMAL passes every SQLite suite.
249
+
250
+ ## Money and rates
251
+
252
+ - **Money is integer minor units** (cents) — `$19.99` is `1999`.
253
+ `SupportPlan.availabilityFeeAmount`, `SupportCharge.amount` and
254
+ `SupportCompensation.amount` initialize `= 0`, never `= 0.0`: the integer
255
+ literal is what maps them to INTEGER columns (BIGINT on fresh PostgreSQL/DuckDB databases; #2401, #2373).
256
+ - **Rates stay DECIMAL but their unit changed.**
257
+ `SupportPlan.overageHourlyRate` / `onCallHourlyRate` and
258
+ `SupportCompensationPlan.hourlyRate` are **minor units per hour**, so
259
+ `hours * rate` yields minor units. INTEGER would truncate a sub-unit rate to
260
+ zero, which is why they keep a decimal initializer.
261
+ - **`roundMoney()` is the single rate↔money boundary.** It rounds
262
+ `(seconds / 3600) * hourlyRate` to a whole minor unit, which is what lets the
263
+ `thresholdAmount` comparison in `determinePath()` be an exact `>` with no
264
+ tolerance. `TimeApprovalPolicy.thresholdAmount` is in the same unit as
265
+ `SupportCharge.amount`.
266
+ - **Migrating an existing database**: `preflightSupportMoneyMinorUnits(db)`
267
+ reports which columns still hold major units and which rows would be rounded
268
+ or exceed JavaScript's safe-integer range; `migrateSupportMoneyToMinorUnits(db)` converts them
269
+ (idempotent via `_smrt_backfills`). The **rate columns are not in that list**
270
+ — their type does not change, but their stored values must still be
271
+ multiplied by the same scale in the same deploy step. Frozen `rateSnapshot`
272
+ JSON on settled charges is history and is left alone. On SQLite the values
273
+ are rescaled but the declared type needs the table-rebuild path (#2370).
274
+ Fresh PostgreSQL/DuckDB INTEGER columns are BIGINT and hydration rejects
275
+ values outside JavaScript's safe-integer range; existing PostgreSQL `int4`
276
+ columns require #2424.
277
+
245
278
  ## Gotchas
246
279
 
247
280
  - **Writes go through the facades** — the case-side generated routes are
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { migrateSupportMoneyToMinorUnits, preflightSupportMoneyMinorUnits, SUPPORT_MONEY_COLUMNS, SUPPORT_MONEY_MINOR_UNITS_BACKFILL, } from './migrations/moneyMinorUnits.js';
1
2
  export * from './models/index.js';
2
3
  export { APPROVE_TIME_ENTRY_PERMISSION, ensureSupportPermissionsRegistered, MANAGE_PLANS_PERMISSION, REASSIGN_CASE_PERMISSION, registerSupportPermissions, SUPPORT_PERMISSION_DEFS, type SupportPrincipal, supportPrincipalFromPermissions, } from './permissions.js';
3
4
  export * from './services/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,wBAAwB,CAAC;AAIhC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,+BAA+B,GAChC,MAAM,kBAAkB,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,wBAAwB,CAAC;AAKhC,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,EAC/B,qBAAqB,EACrB,kCAAkC,GACnC,MAAM,iCAAiC,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,EAClC,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,+BAA+B,GAChC,MAAM,kBAAkB,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC"}