feat(backend): harden draft, pricing and publish contracts

- unify typed API errors across draft, pricing and publish flows
- add stale draft and publish-state mutation guards
- add publish readiness contract and guarded publish flow
- add sellability reason codes to test seat preview
- add pricing diagnostics and strengthen snapshot/publish lifecycle consistency
This commit is contained in:
greebo
2026-03-19 20:58:14 +03:00
parent ac3a62f108
commit a266f56ddd
6 changed files with 368 additions and 297 deletions

View File

@@ -1,52 +1,55 @@
from pydantic import BaseModel
class PricingCoverageResponse(BaseModel):
scheme_id: str
scheme_version_id: str
total_seats: int
priced_seats: int
unpriced_seats: int
coverage_percent: float
class UnpricedSeatItem(BaseModel):
seat_record_id: str
seat_id: str | None
element_id: str | None
sector_id: str | None
group_id: str | None
row_label: str | None
seat_number: str | None
reason_code: str
reason_message: str
class UnpricedSeatListResponse(BaseModel):
scheme_id: str
scheme_version_id: str
total: int
items: list[UnpricedSeatItem]
class ExplainMatchedRule(BaseModel):
matched_rule_level: str
matched_target_ref: str
class PricingCategoryMutationResponse(BaseModel):
pricing_category_id: str
scheme_id: str
name: str
code: str
class PricingCategoryDeleteResponse(BaseModel):
deleted: bool
pricing_category_id: str
class PriceRuleMutationResponse(BaseModel):
price_rule_id: str
scheme_id: str
pricing_category_id: str
target_type: str
target_ref: str
amount: str
currency: str
class ExplainSeatPriceResponse(BaseModel):
class PriceRuleDeleteResponse(BaseModel):
deleted: bool
price_rule_id: str
class PricingRuleDiagnosticsItem(BaseModel):
price_rule_id: str
pricing_category_id: str
target_type: str
target_ref: str
amount: str
currency: str
matched_seats_count: int
matched_seat_ids: list[str]
orphan: bool
orphan_reason: str | None
class PricingRuleDiagnosticsSummary(BaseModel):
total_rules: int
orphan_rules_count: int
active_rules_count: int
matched_seats_total: int
class PricingRuleDiagnosticsResponse(BaseModel):
scheme_id: str
scheme_version_id: str
seat_id: str
element_id: str | None
sector_id: str | None
group_id: str | None
row_label: str | None
seat_number: str | None
has_price: bool
reason_code: str
reason_message: str
matched_rule: ExplainMatchedRule | None
summary: PricingRuleDiagnosticsSummary
items: list[PricingRuleDiagnosticsItem]