Variable: PriceTierFormValue
const PriceTierFormValue: ZodObject<{
capacityRules: ZodArray<ZodObject<{
operator: ZodEnum<{
between: "between";
greater_than: "greater_than";
less_than: "less_than";
}>;
secondValue: ZodNullable<ZodNumber>;
value: ZodNumber;
}, $strip>>;
defaultPrice: ZodOptional<ZodObject<{
amountCents: ZodNullable<ZodNumber>;
durationUnit: ZodOptional<ZodNullable<ZodEnum<{
day: "day";
hour: "hour";
night: "night";
}>>>;
isFree: ZodBoolean;
pricingUnit: ZodEnum<{
day: "day";
flat: "flat";
hour: "hour";
month: "month";
night: "night";
person: "person";
unit: "unit";
year: "year";
}>;
}, $strip>>;
description: ZodNullable<ZodString>;
maxQuantity: ZodOptional<ZodNullable<ZodNumber>>;
membershipTierId: ZodNullable<ZodString>;
name: ZodString;
requireMembership: ZodBoolean;
requireResidency: ZodBoolean;
residencyType: ZodNullable<ZodEnum<{
city: "city";
state: "state";
zip_code: "zip_code";
}>>;
residencyValues: ZodArray<ZodString>;
}, $strip>;Defined in: shared/pricing/types/tier-form.ts:230
The value the "Add/Edit Price Tier" modal (PriceTierDialog, PLA-139)
collects and hands back through its onSubmit callback. This is the
client↔consumer contract only — NOT a persistence shape. The consumer's own
backend procedure translates it into the real PricingMatrixService calls:
name/description→addRateTier/updateRateTier.requireMembership+membershipTierId→ aFIELD_COMPARISONeqcondition, whose id is passed inaddRateTier/updateRateTierRequirements'srequirementConditionIds.requireResidency+residencyType+residencyValues→ a singleFIELD_COMPARISONincondition whosefieldis chosen byresidencyTypeand whosevalueisresidencyValues.defaultPrice→ TWO calls, because the stored default and the existing cells are different things. Pass it asaddRateTier/updateRateTier'sdefaultPriceso the tier remembers it and future schedule columns get seeded; then, if you want the columns that ALREADY exist to take it, callsetCellPricefor each. The stored default deliberately never overwrites an existing cell, so that second step is the caller's explicit choice rather than a side effect. MapisFreetoamountCents: 0(the matrix expresses free as priced-at-zero), and a null amount on a non-free value todefaultPrice: null(no default).defaultPrice.durationUnitgoes on BOTH halves —defaultPrice.peron the tier (so the fallback price and any later-seeded column carry the axis) andperon eachsetCellPrice. SeePriceTierDefaultPrice.durationUnit.capacityRules→ oneGROUP_SIZEcondition each, referenced by id inrequirementConditionIds(empty array = no capacity constraint). SeeCapacityRule.maxQuantity→ NO taproot call. The one field with noPricingMatrixServicedestination: purchase-quantity caps are order-time data, not pricing data (PLA-233), so you persist it yourself and enforce it withassertTierQuantityLimitsat your own write boundary. See the field's doc.
The superRefine enforces the cross-field invariants so a server consumer
can trust parse (the dialog can't be the only guard): a requirement toggle
that's on must carry its data, and one that's off must not carry stale data.