Liking cljdoc? Tell your friends :D

urpx.price

Resolve applicable per-energy prices for a URPX rate plan at a given instant.

Given a coerced rate plan (urpx.coerce/coerce-rate-plan) and a ZonedDateTime, resolve-prices returns the season, the matched TOU period (if any), and one entry per active per-energy ledger (commodity, distribution, public benefits, etc.). Each ledger entry carries a :tiers vector — for block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is surfaced so the caller can pick the active one based on cumulative usage; for non-tiered ledgers the vector has a single entry.

Skipped:

  • PriceDefinitions whose own :urpx/hasCalculationMethod is set (recurring fixed charges like a monthly customer charge — these are subscription-style and don't apply to instantaneous lookup).

Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays, urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays booleans (both default to true when omitted). Holiday detection sources, in priority order:

  1. Explicit :holiday? predicate in opts (highest precedence — overrides).
  2. The plan's embedded urpx:HolidayCalendar, derived via urpx.holidays/derive-predicate.
  3. Fallback: every date treated as a non-holiday.

Plans without a HolidayCalendar and called without :holiday? retain the pre-existing 'every date is a non-holiday' fallback — so brackets that opt out of non-holidays (urpx:includeNonHolidays = false) will never match.

Resolve applicable per-energy prices for a URPX rate plan at a given instant.

Given a coerced rate plan (`urpx.coerce/coerce-rate-plan`) and a
ZonedDateTime, `resolve-prices` returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a `:tiers` vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.

Skipped:
  - PriceDefinitions whose own `:urpx/hasCalculationMethod` is set
    (recurring fixed charges like a monthly customer charge — these are
    subscription-style and don't apply to instantaneous lookup).

Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays,
urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the
TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays
booleans (both default to true when omitted). Holiday detection sources,
in priority order:

  1. Explicit `:holiday?` predicate in opts (highest precedence — overrides).
  2. The plan's embedded urpx:HolidayCalendar, derived via
     `urpx.holidays/derive-predicate`.
  3. Fallback: every date treated as a non-holiday.

Plans without a HolidayCalendar and called without `:holiday?` retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.
raw docstring

has-energy-ledger?clj

(has-energy-ledger? resolved)

True if resolved carries any ledger measured in urpx:energy, which is the precondition for marginal-unit-rate returning a number.

Ask this before calling it when sweeping a corpus. Plenty of real schedules price nothing per kWh (street lighting, fixed service charges), and for those a marginal per-kWh rate is not a small number, it is a question that does not apply.

True if `resolved` carries any ledger measured in urpx:energy, which is the
precondition for `marginal-unit-rate` returning a number.

Ask this before calling it when sweeping a corpus. Plenty of real schedules
price nothing per kWh (street lighting, fixed service charges), and for those
a marginal per-kWh rate is not a small number, it is a question that does not
apply.
raw docstring

marginal-unit-rateclj

(marginal-unit-rate resolved)
(marginal-unit-rate resolved opts)

The marginal $/kWh at the start of a billing period: summed across all energy ledgers, and within each ledger the sum of its ADDITIVE rate components plus the LOWEST rung of its block tier ladder, if it has one.

A ledger is used for two different things in practice. A block tier ladder is mutually exclusive, so only the marginal rung counts; an additive rate stack (a delivery ledger carrying transmission, distribution, public purpose and the rest) is cumulative, so all of it counts. urpx:serviceTierNumber is what separates them: a numbered tier belongs to a ladder, a bare one is a component. URPX has no vocabulary saying which a ledger is, so this is the signal available rather than the signal designed, and a ledger mixing both contributes its components plus the lowest rung of that ladder.

A ledger is treated as energy iff its referenced MetricInput's urpx:measurementKind is urpx:energy. Per-meter, per-customer, per-day, or per-month service charges (urpx:profileMetricInput, or non-energy measurementKinds) are excluded — they have a different shape and don't belong in a $/kWh sum.

Useful for price signaling: when you don't know a customer's usage but want a single $/kWh number, this is the marginal rate at zero baseline usage.

REFUSES, rather than returning a number, in six cases, each carrying a named :reason in its ex-data so a sweeping consumer can classify:

:no-energy-ledger this plan prices nothing per kWh, so the question does not apply to it. 0M would be indistinguishable from a plan whose energy ledgers genuinely sum to zero :unvaluable-marginal-tier a marginal tier could not be valued. A nil unit price reads to a consumer as free, and for a discount that is the worst available answer :unselected-alternatives an energy ledger carries mutually-exclusive price alternatives with no caller selection, AND either at least one of the withheld prices would have entered this sum, or nothing is recorded about what was withheld. Withholding a price the sum would not have taken costs the caller nothing and does not refuse; not KNOWING what was withheld is not evidence that it did not matter, so that refuses :condition-gated-tier a price in the sum is gated by a urpx:ConditionExpression this library does not evaluate, so including it would report an assumption as a number. Pass :assume-conditions-hold? true for the every-condition-true upper bound :all-energy-tiers-excluded every energy tier was event-driven, recurring, or both. Free is not the answer either :outside-version-window the version used does not describe this instant

The alternatives case is why composing a PG&E plan with its vintage-PCIA modifier needs :profile-alternatives. Taking the first of eighteen mutually exclusive prices added an arbitrary 0.02973 to the rate; the eighteen span 0.06391/kWh, so there is no default worth inventing.

EVENT-DRIVEN PRICES ARE EXCLUDED BY DEFAULT. A Price carrying urpx:hasDynamicPricing applies only while its event is called: a critical peak charge is real but exceptional, capped around 50 hours a summer against roughly 2,200 summer hours. Summing it unconditionally answered what would this cost during an event', which read as the ordinary rate. The default is now the non-event baseline, which is what a price signal means bythe next kWh'. Unlike the alternatives above there IS a defensible default here, because no-event-today is the ordinary state rather than an arbitrary pick.

Pass {:include-dynamic-pricing? true} for the during-event upper bound. Either way :urpx.resolved/dynamic-pricing on the tier says which prices are event-driven, so a caller can compute both.

The marginal $/kWh at the start of a billing period: summed across all
**energy** ledgers, and within each ledger the sum of its ADDITIVE rate
components plus the LOWEST rung of its block tier ladder, if it has one.

A ledger is used for two different things in practice. A block tier ladder
is mutually exclusive, so only the marginal rung counts; an additive rate
stack (a delivery ledger carrying transmission, distribution, public purpose
and the rest) is cumulative, so all of it counts. urpx:serviceTierNumber is
what separates them: a numbered tier belongs to a ladder, a bare one is a
component. URPX has no vocabulary saying which a ledger is, so this is the
signal available rather than the signal designed, and a ledger mixing both
contributes its components plus the lowest rung of that ladder.

A ledger is treated as energy iff its referenced MetricInput's
urpx:measurementKind is urpx:energy. Per-meter, per-customer, per-day, or
per-month service charges (urpx:profileMetricInput, or non-energy
measurementKinds) are excluded — they have a different shape and don't
belong in a $/kWh sum.

Useful for price signaling: when you don't know a customer's usage but want
a single $/kWh number, this is the marginal rate at zero baseline usage.

REFUSES, rather than returning a number, in six cases, each carrying a
named `:reason` in its ex-data so a sweeping consumer can classify:

  :no-energy-ledger            this plan prices nothing per kWh, so the
                               question does not apply to it. 0M would be
                               indistinguishable from a plan whose energy
                               ledgers genuinely sum to zero
  :unvaluable-marginal-tier    a marginal tier could not be valued. A nil
                               unit price reads to a consumer as free, and
                               for a discount that is the worst available
                               answer
  :unselected-alternatives     an energy ledger carries mutually-exclusive
                               price alternatives with no caller selection,
                               AND either at least one of the withheld prices
                               would have entered this sum, or nothing is
                               recorded about what was withheld. Withholding
                               a price the sum would not have taken costs the
                               caller nothing and does not refuse; not
                               KNOWING what was withheld is not evidence that
                               it did not matter, so that refuses
  :condition-gated-tier        a price in the sum is gated by a
                               urpx:ConditionExpression this library does not
                               evaluate, so including it would report an
                               assumption as a number. Pass
                               :assume-conditions-hold? true for the
                               every-condition-true upper bound
  :all-energy-tiers-excluded   every energy tier was event-driven, recurring,
                               or both. Free is not the answer either
  :outside-version-window      the version used does not describe this
                               instant

The alternatives case is why composing a PG&E plan with its vintage-PCIA
modifier needs `:profile-alternatives`. Taking the first of eighteen mutually
exclusive prices added an arbitrary 0.02973 to the rate; the eighteen span
0.06391/kWh, so there is no default worth inventing.

EVENT-DRIVEN PRICES ARE EXCLUDED BY DEFAULT. A Price carrying
urpx:hasDynamicPricing applies only while its event is called: a critical
peak charge is real but exceptional, capped around 50 hours a summer against
roughly 2,200 summer hours. Summing it unconditionally answered `what would
this cost during an event', which read as the ordinary rate. The default is
now the non-event baseline, which is what a price signal means by `the next
kWh'. Unlike the alternatives above there IS a defensible default here,
because no-event-today is the ordinary state rather than an arbitrary pick.

Pass `{:include-dynamic-pricing? true}` for the during-event upper bound.
Either way `:urpx.resolved/dynamic-pricing` on the tier says which prices
are event-driven, so a caller can compute both.
raw docstring

measurement-kindsclj

(measurement-kinds resolved)

The set of urpx:measurementKind @ids present across resolved's ledgers.

What a caller usually wants to know, having found that a plan prices nothing per kWh, is what it DOES price in, so this answers with the kinds rather than a bare yes or no and lets a sweeping consumer route instead of merely skip.

May be empty. CPAU E-14 is the case: a street lighting schedule whose charges are all per-lamp-per-month and per-fixture-per-month, filed as recurring charges with their own CalculationMethod, which price resolution excludes. Nothing resolves, so nothing is reported, and an empty set says exactly that.

The set of urpx:measurementKind @ids present across `resolved`'s ledgers.

What a caller usually wants to know, having found that a plan prices nothing
per kWh, is what it DOES price in, so this answers with the kinds rather than
a bare yes or no and lets a sweeping consumer route instead of merely skip.

May be empty. CPAU E-14 is the case: a street lighting schedule whose charges
are all per-lamp-per-month and per-fixture-per-month, filed as recurring
charges with their own CalculationMethod, which price resolution excludes.
Nothing resolves, so nothing is reported, and an empty set says exactly that.
raw docstring

plan-zoneclj

(plan-zone doc)

The ZoneId a plan or modifier declares as urpx:timezoneIdentifier, or nil.

THE ZONE EVERY BOUND IN A URPX DOCUMENT IS WRITTEN IN. urpx:effectiveDateTime, urpx:expirationDateTime and every TOU bracket are naive wall-clock readings: measured across the production corpus, all 89 carry no offset. They are wall-clock IN THIS ZONE, so reading them in any other is reading a different moment.

Present on all 72 production filings, on the urpx:RatePlan in 39 and the urpx:RatePlanModifier in 41, so both halves of a composition can be zoned.

The ZoneId a plan or modifier declares as urpx:timezoneIdentifier, or nil.

THE ZONE EVERY BOUND IN A URPX DOCUMENT IS WRITTEN IN. urpx:effectiveDateTime,
urpx:expirationDateTime and every TOU bracket are naive wall-clock readings:
measured across the production corpus, all 89 carry no offset. They are
wall-clock IN THIS ZONE, so reading them in any other is reading a different
moment.

Present on all 72 production filings, on the urpx:RatePlan in 39 and the
urpx:RatePlanModifier in 41, so both halves of a composition can be zoned.
raw docstring

require-zoneclj

(require-zone doc)

The plan's declared zone, or REFUSE.

A document that states no zone states no moment: its bounds are wall-clock readings with nothing to anchor them, so whether an instant falls inside one has no answer. Falling back to the caller's zone is what this replaces, and it silently made the answer depend on how the caller spelled the instant.

The plan's declared zone, or REFUSE.

A document that states no zone states no moment: its bounds are wall-clock
readings with nothing to anchor them, so whether an instant falls inside one
has no answer. Falling back to the caller's zone is what this replaces, and
it silently made the answer depend on how the caller spelled the instant.
raw docstring

resolve-modifier-pricesclj

(resolve-modifier-prices modifier zdt)

Resolve every per-energy unit price that modifier (a coerced urpx:RatePlanModifier) contributes at zdt.

Returns the same shape as resolve-prices minus the season/TOU keys (modifier ledgers are flat add-ons): {:urpx.resolved/ledgers [...]}.

When the modifier carries its own urpx:hasTOUSchedule, PDs with :urpx/touPeriodNumber are gated against the modifier's resolved period. Without an own TOUSchedule and no base context, every applicable Price is surfaced — matrix-style modifiers (e.g. CPAU E-HRA — 4x4 reserve level x generation tier driven by external state) rely on this so the caller can select the active value, since the URPX condition vocabulary (operator + label conditionValue) is not yet specified in a way that's programmatically interpretable. Filter the returned :tiers vector on :urpx.resolved/price-id when needed.

Resolve every per-energy unit price that `modifier` (a coerced
urpx:RatePlanModifier) contributes at `zdt`.

Returns the same shape as `resolve-prices` minus the season/TOU keys
(modifier ledgers are flat add-ons): {:urpx.resolved/ledgers [...]}.

When the modifier carries its own urpx:hasTOUSchedule, PDs with
:urpx/touPeriodNumber are gated against the modifier's resolved period.
Without an own TOUSchedule and no base context, every applicable Price
is surfaced — matrix-style modifiers (e.g. CPAU E-HRA — 4x4 reserve
level x generation tier driven by external state) rely on this so the
caller can select the active value, since the URPX condition
vocabulary (operator + label conditionValue) is not yet specified in a
way that's programmatically interpretable. Filter the returned :tiers
vector on :urpx.resolved/price-id when needed.
raw docstring

resolve-pricesclj

(resolve-prices rate-plan zdt)
(resolve-prices rate-plan zdt opts)

Resolve all per-energy unit prices that apply to rate-plan at zdt (a java.time.ZonedDateTime in the rate plan's local timezone).

Optional opts map: :holiday? predicate (LocalDate -> bool) used to evaluate a bracket's urpx:includeHolidays / urpx:includeNonHolidays gates. A plain set of LocalDates works (sets are functions). When omitted, a predicate is derived from the plan's embedded urpx:HolidayCalendar via urpx.holidays/derive-predicate; if neither is available, every date is treated as a non-holiday — so brackets that opt out of non-holidays (urpx:includeNonHolidays = false, e.g. holiday-only off-peak overrides) will never match.

:profile-alternatives a {<ProfileAlternatives @id> <ProfileAlternative @id>} map driving customer-profile-driven price selection, keyed by the ProfileAlternatives CONTAINER. It scopes both Prices.hasPriceSetAlternatives (income-tier CARE/FERA/Standard, vintage-PCIA departure year, voltage configuration) and PriceDefinition.referencesProfileAlternative.

         A dimension the caller says nothing about is NOT skipped: its
         prices are withheld, the ledger carries
         :urpx.resolved/unselected-alternatives, and marginal-unit-rate
         refuses if withholding them would make its sum short. A value
         the keyed container does not list is refused outright, since
         compared for equality a stale id is indistinguishable from a
         deliberate choice of some other cell.

         Programmatic ConditionExpression evaluation against a customer
         profile is a future enhancement; a consumer names the cell.

Examples of :holiday?:

;; Most rate plans embed urpx:HolidayCalendar — no opts needed: (resolve-prices plan zdt)

;; Static set — overrides any embedded calendar: (def us-federal-2026 #{(LocalDate/of 2026 1 1) ; New Year's Day (LocalDate/of 2026 1 19) ; Martin Luther King Jr. Day (LocalDate/of 2026 2 16) ; Presidents Day (LocalDate/of 2026 5 25) ; Memorial Day (LocalDate/of 2026 6 19) ; Juneteenth (LocalDate/of 2026 7 3) ; Independence Day (observed) (LocalDate/of 2026 9 7) ; Labor Day (LocalDate/of 2026 11 11) ; Veterans Day (LocalDate/of 2026 11 26) ; Thanksgiving (LocalDate/of 2026 12 25)}) ; Christmas (resolve-prices plan zdt {:holiday? us-federal-2026})

;; Composed predicate — if you maintain a calendar elsewhere: (resolve-prices plan zdt {:holiday? (fn [d] (calendar/observed? :us-federal d))})

Returns: {:urpx.resolved/season-name String or nil :urpx.resolved/tou-period-name String or nil :urpx.resolved/tou-period-number int or nil :urpx.resolved/ledgers [LedgerResult]}

where each LedgerResult is: {:urpx.resolved/ledger-id String :urpx.resolved/ledger-name String :urpx.resolved/ledger-type Ref :urpx.resolved/metric-input-id String (when the ledger references one) :urpx.resolved/metric-input-type Ref (e.g. urpx:measuredMetricInput) :urpx.resolved/measurement-kind Ref (e.g. urpx:energy — present when the MetricInput carries one; marginal-unit-rate filters on this) :urpx.resolved/unit-of-measure Ref (e.g. urpx:kWh) :urpx.resolved/tiers [TierResult] :urpx.resolved/unselected-alternatives [String] (present iff prices on this ledger belong to alternatives the caller chose none of) :urpx.resolved/withheld-prices [WithheldPrice] (what those alternatives would have priced, enough of it to say whether a marginal sum is actually short)}

and each TierResult is: {:urpx.resolved/price-definition-id String :urpx.resolved/price-id String :urpx.resolved/price-name String :urpx.resolved/unit-price BigDecimal :urpx.resolved/tier-number int (only on block-tiered ledgers) :urpx.resolved/tier-name String :urpx.resolved/tier-lower-bound BigDecimal :urpx.resolved/tier-upper-bound BigDecimal :urpx.resolved/tier-lower-bound-operator Ref :urpx.resolved/tier-upper-bound-operator Ref :urpx.resolved/dynamic-pricing Map (present iff the source Price carries urpx:hasDynamicPricing — a CPP Event Charge, RTP price, or other event-driven component; consumers that need a non-event marginal rate filter on the absence of this key) :urpx.resolved/condition-gated [Gate] (present iff the source Price or its PriceDefinition carries a urpx:ConditionExpression this library does not evaluate, so the price fired on an ASSUMPTION that its predicate holds. Each Gate carries :gate-id, :gate-name and :gate-on, the last being :price or :price-definition. Not excluded from any aggregate: see marginal-unit-rate)}

For non-tiered ledgers, :tiers has a single entry with no tier-* keys. For block-tiered ledgers (e.g. CPAU E-1), :tiers carries every tier sorted by tier-number — the caller chooses based on cumulative billing-period usage.

Resolve all per-energy unit prices that apply to `rate-plan` at `zdt`
(a java.time.ZonedDateTime in the rate plan's local timezone).

Optional `opts` map:
  :holiday?  predicate `(LocalDate -> bool)` used to evaluate a bracket's
             urpx:includeHolidays / urpx:includeNonHolidays gates. A plain
             set of LocalDates works (sets are functions). When omitted,
             a predicate is derived from the plan's embedded
             urpx:HolidayCalendar via `urpx.holidays/derive-predicate`;
             if neither is available, every date is treated as a
             non-holiday — so brackets that opt out of non-holidays
             (urpx:includeNonHolidays = false, e.g. holiday-only off-peak
             overrides) will never match.

  :profile-alternatives  a {<ProfileAlternatives @id> <ProfileAlternative @id>}
             map driving customer-profile-driven price selection, keyed by
             the ProfileAlternatives CONTAINER. It scopes both
             Prices.hasPriceSetAlternatives (income-tier CARE/FERA/Standard,
             vintage-PCIA departure year, voltage configuration) and
             PriceDefinition.referencesProfileAlternative.

             A dimension the caller says nothing about is NOT skipped: its
             prices are withheld, the ledger carries
             :urpx.resolved/unselected-alternatives, and marginal-unit-rate
             refuses if withholding them would make its sum short. A value
             the keyed container does not list is refused outright, since
             compared for equality a stale id is indistinguishable from a
             deliberate choice of some other cell.

             Programmatic ConditionExpression evaluation against a customer
             profile is a future enhancement; a consumer names the cell.

Examples of `:holiday?`:

  ;; Most rate plans embed urpx:HolidayCalendar — no opts needed:
  (resolve-prices plan zdt)

  ;; Static set — overrides any embedded calendar:
  (def us-federal-2026
    #{(LocalDate/of 2026 1 1)    ; New Year's Day
      (LocalDate/of 2026 1 19)   ; Martin Luther King Jr. Day
      (LocalDate/of 2026 2 16)   ; Presidents Day
      (LocalDate/of 2026 5 25)   ; Memorial Day
      (LocalDate/of 2026 6 19)   ; Juneteenth
      (LocalDate/of 2026 7 3)    ; Independence Day (observed)
      (LocalDate/of 2026 9 7)    ; Labor Day
      (LocalDate/of 2026 11 11)  ; Veterans Day
      (LocalDate/of 2026 11 26)  ; Thanksgiving
      (LocalDate/of 2026 12 25)})  ; Christmas
  (resolve-prices plan zdt {:holiday? us-federal-2026})

  ;; Composed predicate — if you maintain a calendar elsewhere:
  (resolve-prices plan zdt {:holiday? (fn [d] (calendar/observed? :us-federal d))})

Returns:
  {:urpx.resolved/season-name      String or nil
   :urpx.resolved/tou-period-name  String or nil
   :urpx.resolved/tou-period-number int or nil
   :urpx.resolved/ledgers          [LedgerResult]}

where each LedgerResult is:
  {:urpx.resolved/ledger-id           String
   :urpx.resolved/ledger-name         String
   :urpx.resolved/ledger-type         Ref
   :urpx.resolved/metric-input-id     String  (when the ledger references one)
   :urpx.resolved/metric-input-type   Ref     (e.g. urpx:measuredMetricInput)
   :urpx.resolved/measurement-kind    Ref     (e.g. urpx:energy — present when
                                               the MetricInput carries one;
                                               marginal-unit-rate filters on this)
   :urpx.resolved/unit-of-measure     Ref     (e.g. urpx:kWh)
   :urpx.resolved/tiers               [TierResult]
   :urpx.resolved/unselected-alternatives [String]
                                            (present iff prices on this
                                             ledger belong to alternatives
                                             the caller chose none of)
   :urpx.resolved/withheld-prices     [WithheldPrice]
                                            (what those alternatives would
                                             have priced, enough of it to
                                             say whether a marginal sum is
                                             actually short)}

and each TierResult is:
  {:urpx.resolved/price-definition-id String
   :urpx.resolved/price-id             String
   :urpx.resolved/price-name           String
   :urpx.resolved/unit-price           BigDecimal
   :urpx.resolved/tier-number          int      (only on block-tiered ledgers)
   :urpx.resolved/tier-name            String
   :urpx.resolved/tier-lower-bound     BigDecimal
   :urpx.resolved/tier-upper-bound     BigDecimal
   :urpx.resolved/tier-lower-bound-operator Ref
   :urpx.resolved/tier-upper-bound-operator Ref
   :urpx.resolved/dynamic-pricing      Map      (present iff the source Price
                                                 carries urpx:hasDynamicPricing
                                                 — a CPP Event Charge, RTP
                                                 price, or other event-driven
                                                 component; consumers that
                                                 need a non-event marginal
                                                 rate filter on the absence
                                                 of this key)
   :urpx.resolved/condition-gated     [Gate]   (present iff the source Price
                                                 or its PriceDefinition
                                                 carries a
                                                 urpx:ConditionExpression
                                                 this library does not
                                                 evaluate, so the price fired
                                                 on an ASSUMPTION that its
                                                 predicate holds. Each Gate
                                                 carries :gate-id, :gate-name
                                                 and :gate-on, the last being
                                                 :price or :price-definition.
                                                 Not excluded from any
                                                 aggregate: see
                                                 marginal-unit-rate)}

For non-tiered ledgers, :tiers has a single entry with no tier-* keys.
For block-tiered ledgers (e.g. CPAU E-1), :tiers carries every tier sorted
by tier-number — the caller chooses based on cumulative billing-period usage.
raw docstring

resolve-prices-with-modifiersclj

(resolve-prices-with-modifiers rate-plan modifiers zdt)
(resolve-prices-with-modifiers rate-plan modifiers zdt opts)

Resolve prices for rate-plan at zdt and append ledger results for each modifier in modifiers whose :urpx/applicableToRatePlan list includes the base plan's @id. Modifiers whose target lists don't include the plan are silently skipped.

Returns the resolve-prices shape with :urpx.resolved/ledgers extended by the modifier ledgers.

Resolve prices for `rate-plan` at `zdt` and append ledger results for
each modifier in `modifiers` whose :urpx/applicableToRatePlan list
includes the base plan's @id. Modifiers whose target lists don't include
the plan are silently skipped.

Returns the `resolve-prices` shape with :urpx.resolved/ledgers extended
by the modifier ledgers.
raw docstring

version-covers?clj

(version-covers? version t zone)

True if version describes the instant t: in effect by then, and not expired.

t is a ZonedDateTime and the document's naive bounds are anchored in zone first, so the comparison is between MOMENTS. Comparing wall clocks instead answers a different question, and was how the same instant asked in two zones resolved differently: an LA-midnight expiry covered 2025-12-31T20:00-08:00 and refused the identical 2026-01-01T04:00Z.

Public as the single reader of a version window, so a caller asking whether a snapshot is current gets the same answer this namespace uses to resolve it.

A version stating no effective instant covers everything. It cannot be ordered against anything and nothing says it has not started, so refusing it would reject a conformant document over a case the vocabulary permits.

True if `version` describes the instant `t`: in effect by then, and not
expired.

`t` is a ZonedDateTime and the document's naive bounds are anchored in `zone`
first, so the comparison is between MOMENTS. Comparing wall clocks instead
answers a different question, and was how the same instant asked in two zones
resolved differently: an LA-midnight expiry covered 2025-12-31T20:00-08:00
and refused the identical 2026-01-01T04:00Z.

Public as the single reader of a version window, so a caller asking whether
a snapshot is current gets the same answer this namespace uses to resolve it.

A version stating no effective instant covers everything. It cannot be
ordered against anything and nothing says it has not started, so refusing
it would reject a conformant document over a case the vocabulary permits.
raw docstring

version-effective-atclj

(version-effective-at version zone)

The instant version takes effect, as a ZonedDateTime in zone, or nil if it does not say.

ZONE REQUIRED, NOT OPTIONAL. The document states a naive wall-clock reading; it names a moment only once anchored, and every zone anchors it to a different one. An optional zone would make the unzoned call the easy one and the wrong one, which is how this namespace came to compare a caller's wall clock against a publisher's. urpx:effectiveDateTime is preferred; urpx:effectiveDate is read as the start of that day. Both are sh:minCount 0, so a conformant version may state neither, and this returns nil rather than inventing an epoch for it.

Public as THE SINGLE READER of a version's effective instant. urpx.arrangements re-derived this and got it subtly wrong, requiring urpx:effectiveDateTime and so silently dropping a conformant version that states only urpx:effectiveDate. Two namespaces disagreeing about the same date is the drift this prevents.

The instant `version` takes effect, as a ZonedDateTime in `zone`, or nil if
it does not say.

ZONE REQUIRED, NOT OPTIONAL. The document states a naive wall-clock reading;
it names a moment only once anchored, and every zone anchors it to a
different one. An optional zone would make the unzoned call the easy one and
the wrong one, which is how this namespace came to compare a caller's wall
clock against a publisher's. urpx:effectiveDateTime is preferred; urpx:effectiveDate is read as the
start of that day. Both are sh:minCount 0, so a conformant version may state
neither, and this returns nil rather than inventing an epoch for it.

Public as THE SINGLE READER of a version's effective instant. urpx.arrangements
re-derived this and got it subtly wrong, requiring urpx:effectiveDateTime and
so silently dropping a conformant version that states only urpx:effectiveDate.
Two namespaces disagreeing about the same date is the drift this prevents.
raw docstring

version-expired-by?clj

(version-expired-by? version t zone)

True if version states a hard expiration at or before t.

t is a ZonedDateTime and the bound is anchored in zone before comparing, so the answer is about one MOMENT rather than about two wall clocks that may be in different places.

Public alongside version-effective-at, and for the same reason: it is the single reader of a version's end bound.

urpx:expirationDate / urpx:expirationDateTime only. The version shapes also carry urpx:expectedEndDate and urpx:expectedEndDateTime, which are deliberately NOT read here: an expected end anticipates a successor rather than terminating anything, so a version past its expected end is still the one in force until a later version exists. Treating the two alike would silently drop a plan that outlived its own forecast.

True if `version` states a hard expiration at or before `t`.

`t` is a ZonedDateTime and the bound is anchored in `zone` before comparing,
so the answer is about one MOMENT rather than about two wall clocks that may
be in different places.

Public alongside `version-effective-at`, and for the same reason: it is the
single reader of a version's end bound.

urpx:expirationDate / urpx:expirationDateTime only. The version shapes also
carry urpx:expectedEndDate and urpx:expectedEndDateTime, which are
deliberately NOT read here: an expected end anticipates a successor rather
than terminating anything, so a version past its expected end is still the
one in force until a later version exists. Treating the two alike would
silently drop a plan that outlived its own forecast.
raw docstring

version-expires-atclj

(version-expires-at version zone)

The instant version stops applying, as a ZonedDateTime in zone, or nil.

Named rather than inlined because it was re-derived at three call sites and the resolved marks emitted it as a naive LocalDateTime while the comparison used something else. One reader, one type.

The instant `version` stops applying, as a ZonedDateTime in `zone`, or nil.

Named rather than inlined because it was re-derived at three call sites and
the resolved marks emitted it as a naive LocalDateTime while the comparison
used something else. One reader, one type.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close