feat(contracts): add weekly and bi-weekly billing cycles (PMS-404) #308

Merged
vas2000-work merged 2 commits from feat/PMS-404-weekly-biweekly-billing-cycles into main 2026-06-18 04:24:04 +02:00
Owner

Adds weekly and bi_weekly to the contract billing_cycle closed set end to end (PMS-404). Migration 061 drops and re-adds the contracts_billing_cycle_check constraint to the six-value set; BILLING_CYCLES is widened so the request layer returns a clean 422 for a bad cycle instead of a 500. Both start_date-anchored period calculators (period_for for hour-balance windows and current_billing_period for recurring-invoice anchors) now share a CycleStep enum that steps sub-month cycles by whole days (7/14 via chrono::Days) and longer cycles by months (chrono::Months, keeping end-of-month clamping); the recurring sweep already excludes only one_time so weekly/bi_weekly contracts are swept automatically. New contracts integration tests confirm the DB constraint accepts the cycles and hour balances bucket into contiguous 7-day and 14-day windows.

#PMS-404

Adds `weekly` and `bi_weekly` to the contract `billing_cycle` closed set end to end (PMS-404). Migration 061 drops and re-adds the `contracts_billing_cycle_check` constraint to the six-value set; `BILLING_CYCLES` is widened so the request layer returns a clean 422 for a bad cycle instead of a 500. Both start_date-anchored period calculators (`period_for` for hour-balance windows and `current_billing_period` for recurring-invoice anchors) now share a `CycleStep` enum that steps sub-month cycles by whole days (7/14 via chrono::Days) and longer cycles by months (chrono::Months, keeping end-of-month clamping); the recurring sweep already excludes only `one_time` so weekly/bi_weekly contracts are swept automatically. New contracts integration tests confirm the DB constraint accepts the cycles and hour balances bucket into contiguous 7-day and 14-day windows. #PMS-404
feat(contracts): add weekly and bi_weekly billing cycles
Some checks failed
Check / fmt + clippy + compile + unit/doc tests (pull_request) Failing after 5s
E2E / Playwright against staging (pull_request) Successful in 33s
Integration / integration tests (pull_request) Successful in 3m46s
7f0cb05778
Add weekly and bi_weekly as accepted contract billing_cycle values end to end (DB CHECK constraint, request-layer validation, and both period calculators) so weekly and bi-weekly contracts can be created, validated, swept for recurring invoicing, and bucketed for hour-balance periods (PMS-404).

Migration 061_billing_cycle_weekly_biweekly.sql drops and re-adds the auto-named contracts_billing_cycle_check constraint to include 'weekly' and 'bi_weekly'; canonical tokens are snake_case to match the existing one_time convention.

Extend BILLING_CYCLES in src/utils/validation.rs to the six-value set so validate_billing_cycle accepts both new tokens at the request layer (a clear 422 rather than a 500 from the DB CHECK).

Introduce a shared CycleStep enum (pub(crate) in contracts::service) that expresses one period step as either whole days (weekly = 7, bi_weekly = 14, advanced via chrono::Days) or whole months (monthly/quarterly/annually, advanced via chrono::Months so end-of-month overflow clamps). Both period calculators that anchor on start_date now use it: ContractsService::period_for (hour-balance windows) and current_billing_period in the billing service (recurring-invoice anchors). The recurring sweep already excludes only one_time, so weekly/bi_weekly contracts are picked up automatically.

Flip the unit tests in src/modules/contracts/models.rs and src/utils/validation.rs that hard-coded weekly as rejected to assert weekly and bi_weekly are accepted, and add integration tests in tests/contracts.rs verifying the DB constraint accepts the new cycles and consume_hours buckets into contiguous 7-day and 14-day windows.

#PMS-404

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
style: match CI rustfmt in PMS-404 contracts tests (PMS-404)
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 1m40s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 2m0s
Integration / integration tests (pull_request) Successful in 7m15s
Create release / Create release from merged PR (pull_request) Has been skipped
af4472442a
CI runs a rustfmt that expands the consume_hours argument lists and collapses the short period query onto the let line; match it so cargo fmt --check passes.

#PMS-404
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!308
No description provided.