billingTimeline
Signature
Section titled “Signature”billingTimeline(dates: BillingDates, windows: BillingWindows): BillingDeadlines | nullLay out the deadline chain around a demurrage or detention invoice: the last date it may be issued, the last date it may be disputed, and the last date the dispute must be resolved.
- A billing regime or service contract can set up to three windows around an invoice: one to issue it, one to dispute it, and one to resolve the dispute. The number of days in each is the caller’s fact; GMT carries none of them. The arithmetic is this function’s: each deadline is a date, counted in calendar days from a date, with the anchor as day zero and the deadline day itself inside the window.
- Day zero is the anchor and the deadline is
anchor + dayson the ISO 8601 calendar (Temporal.PlainDate.add); a date is “by the deadline” whenTemporal.PlainDate.compare(date, deadline) <= 0. That is this function’s stated contract, not a reading of any rule; a regime that counts differently passes a different number. - Deadlines are dates, never instants. Reduce an instant to the billing party’s local date first with
convertUtcToPlainDate(instant, { timeZone }); this function does not guess a zone.anchorOnis whatever date the caller counts from, such as the last charged date (chargeableDays(...).chargedDates.at(-1)) or, for a party re-billing a charge it was itself billed, the issuance date of the invoice it received. - Windows have no defaults. Each is a safe integer of at least
0; a missing, negative or non-integer window returnsnull, because a silently defaulted window is a wrong deadline. - The chain fills in as its dates exist. With only
anchorOnthe result is a forecast:invoiceDeadlineis set and every other field isnull. An invoice date setsissuedByDeadlineanddisputeDeadline; a request date setsrequestedByDeadlineandresolutionDeadline. An explicitundefinedis an omission; any other value must be a valid ISO date. - The booleans compare dates and say nothing else. Whether a charge is payable, whether a dispute must be heard, and any consequence are the consumer’s. GMT computes dates, not liability.
agreedResolutionOnreplaces the computedresolutionDeadlinewhen given. It must be a valid date on or afterrequestReceivedOn, elsenull; it is validated even when no request exists, but cannot act without one.- A request cannot precede the invoice it disputes.
requestReceivedOnwithoutinvoiceIssuedOn, or earlier than it, is a data error and returnsnull. An invoice earlier than the anchor is allowed: an invoice may be issued while charges still accrue. - Every emitted date is canonical bare ISO (
Temporal.PlainDate#toString()), so an input annotation such as[u-ca=iso8601]does not reach the output, asaddDatebehaves. - Returns
nullwhendatesorwindowsis not an object,anchorOnor a given optional date is not a valid ISO date, a window is missing or not a safe integer of at least0, a request exists without an invoice or before it,agreedResolutionOnis before the request, or a deadline would leave Temporal’s range.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
dates | BillingDates | The anchor date, and the invoice and request dates once they exist |
windows | BillingWindows | The three calendar-day windows, none defaulted, and an agreed resolution date |
Returns
Section titled “Returns”{ invoiceDeadline, issuedByDeadline, disputeDeadline, requestedByDeadline, resolutionDeadline }, or null on invalid input
BillingDates
Section titled “BillingDates”The dates a billing timeline is counted from: the anchor, and the invoice and request once they exist.
import type { BillingDates } from "@northguild/gmt";| Member | Type | Description |
|---|---|---|
anchorOn | string | The date the issue window is counted from, as an ISO date, such as the date the charge was last incurred or, for a re-bill, the issuance date of the invoice received. |
invoiceIssuedOn? | string | The date the invoice was issued, once it has been, as an ISO date. |
requestReceivedOn? | string | The date the dispute request was received, once it has been, as an ISO date. It needs invoiceIssuedOn and may not precede it. |
BillingWindows
Section titled “BillingWindows”The three windows the caller supplies, in calendar days, none defaulted, and an optional agreed resolution date.
import type { BillingWindows } from "@northguild/gmt";| Member | Type | Description |
|---|---|---|
issueDays | number | The days from anchorOn within which the invoice must be issued. |
disputeDays | number | The days from invoiceIssuedOn within which a dispute may be raised. |
resolutionDays | number | The days from requestReceivedOn within which the dispute must be resolved. |
agreedResolutionOn? | string | A resolution date the parties agreed instead, as an ISO date on or after requestReceivedOn; it replaces the computed one. |
BillingDeadlines
Section titled “BillingDeadlines”What billingTimeline returns: each deadline as an ISO date, and each comparison once its date exists.
import type { BillingDeadlines } from "@northguild/gmt";| Member | Type | Description |
|---|---|---|
invoiceDeadline | string | The last date the invoice may be issued: anchorOn + issueDays. |
issuedByDeadline | boolean | null | Whether invoiceIssuedOn is on or before invoiceDeadline; null until an invoice date exists. |
disputeDeadline | string | null | The last date a dispute may be raised: invoiceIssuedOn + disputeDays; null until an invoice date exists. |
requestedByDeadline | boolean | null | Whether requestReceivedOn is on or before disputeDeadline; null until a request date exists. |
resolutionDeadline | string | null | The last date the dispute must be resolved: requestReceivedOn + resolutionDays, or agreedResolutionOn; null until a request date exists. |
Examples
Section titled “Examples”import { billingTimeline } from "@northguild/gmt/intermodal/calculate";
billingTimeline({ anchorOn: "2026-03-01" }, { issueDays: 30, disputeDays: 30, resolutionDays: 30 }) // { invoiceDeadline: "2026-03-31", issuedByDeadline: null, disputeDeadline: null, requestedByDeadline: null, resolutionDeadline: null } (no invoice yet: a forecast)