Compute the next monthly rent charge date
Angular · Angular · advanced · greenfield
Adds the rent-schedule service used by the upcoming-charges panel. `nextChargeDate` decides whether the anchor charge for the last-charged month is already behind (then moves to the following month) and clamps the anchor day into whatever month it lands in, so short months charge on their last day. Walked a 15th-anchor lease across several months and the dates line up.
Property-management SaaS; the charge date drives when tenants' cards are debited.
Requirements
- Add `RentScheduleService.nextChargeDate(lastCharge, anchorDay)` for the property-management app: given the date the rent was last charged and the lease's anchor day, return the date of the charge that FOLLOWS `lastCharge`.
- Rent is charged monthly on the lease's anchor day (`anchorDay`, an integer 1–31 taken from the lease start). In months shorter than the anchor day, the charge lands on the month's last day instead — e.g. anchor 31 charges Jan 31, Feb 28 (or 29), Mar 31.
- The clamping is per-month only: the series must return to the true anchor day in every month long enough to hold it. A charge on Feb 28 for an anchor-31 lease is followed by Mar 31, never Mar 28.
- `lastCharge` is always a date the schedule itself produced (the anchor day clamped into its month), at local midnight; the returned date is at local midnight too.
- All dates are plain local `Date`s; no timezone conversion is involved.
Files touched
- src/app/billing/rent-schedule.service.ts
--- src/app/billing/rent-schedule.service.ts
+import { Injectable } from '@angular/core';
+
+function daysInMonth(year: number, month: number): number {
+ return new Date(year, month + 1, 0).getDate();
+}
+
+@Injectable({ providedIn: 'root' })
+export class RentScheduleService {
+ /**
+ * The charge date following `lastCharge` for a lease anchored on
+ * `anchorDay` (1-31), clamped to month length in short months.
+ */
+ nextChargeDate(lastCharge: Date, anchorDay: number): Date {
+ let year = lastCharge.getFullYear();
+ let month = lastCharge.getMonth();
+ if (lastCharge.getDate() >= anchorDay) {
+ // This month's charge is already behind us — move to the next month.
+ month += 1;
+ if (month > 11) {
+ month = 0;
+ year += 1;
+ }
+ }
+ const day = Math.min(anchorDay, daysInMonth(year, month));
+ return new Date(year, month, day);
+ }
+}
+