fix(loyalty): ProgramCreate accepts null for minimum_purchase_cents
All checks were successful
All checks were successful
The admin program-edit form sends null for empty number inputs. ProgramCreate had minimum_purchase_cents declared as int (default 0, ge=0), which rejected null with 422 — even though the DB column is NOT NULL with default 0 and "0 means no minimum" is the documented semantics. Add a field_validator(mode="before") that coerces None to 0 so the admin form (and any other client that sends null for an empty optional number) goes through cleanly. The other tolerant fields in the schema (stamps_reward_value_cents, points_expiration_days) are already int | None; ProgramUpdate already accepts null here. User hit this after a clean-DB reset prevented falling back to a pre-existing program; the merchant area form happens to send 0 instead of null, masking the bug there. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ Merchant-based programs:
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class PointsRewardConfig(BaseModel):
|
||||
@@ -83,6 +83,13 @@ class ProgramCreate(BaseModel):
|
||||
description="Minimum purchase amount to earn points (0 = no minimum)",
|
||||
)
|
||||
|
||||
@field_validator("minimum_purchase_cents", mode="before")
|
||||
@classmethod
|
||||
def _coerce_purchase_cents_none_to_zero(cls, v):
|
||||
# Form sends null for empty number inputs; DB column is NOT NULL
|
||||
# with default 0, and 0 already means "no minimum" semantically.
|
||||
return 0 if v is None else v
|
||||
|
||||
# Future: Tier configuration
|
||||
tier_config: list[TierConfig] | None = Field(
|
||||
None,
|
||||
|
||||
Reference in New Issue
Block a user