add backend endpoint for publish readiness checks enforce publish gate contract before version publication make publish preconditions explicit and consistent for clients
87 lines
2.8 KiB
Python
87 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
from app.repositories.scheme_seats import list_scheme_version_seats
|
|
from app.repositories.scheme_version_pricing import (
|
|
find_effective_snapshot_price_rule,
|
|
list_scheme_version_snapshot_categories,
|
|
list_scheme_version_snapshot_rules,
|
|
)
|
|
from app.services.scheme_validation import build_scheme_validation_report
|
|
|
|
|
|
async def build_publish_readiness(
|
|
*,
|
|
scheme_id: str,
|
|
scheme_version_id: str,
|
|
require_full_pricing_coverage: bool,
|
|
) -> dict:
|
|
validation = await build_scheme_validation_report(
|
|
scheme_id=scheme_id,
|
|
scheme_version_id=scheme_version_id,
|
|
)
|
|
|
|
seats = await list_scheme_version_seats(scheme_version_id)
|
|
snapshot_categories = await list_scheme_version_snapshot_categories(scheme_version_id)
|
|
snapshot_rules = await list_scheme_version_snapshot_rules(scheme_version_id)
|
|
|
|
snapshot_available = len(snapshot_categories) > 0 or len(snapshot_rules) > 0
|
|
|
|
priced_seats = 0
|
|
unpriced_seats = 0
|
|
|
|
for seat in seats:
|
|
if not seat.seat_id:
|
|
unpriced_seats += 1
|
|
continue
|
|
|
|
if not snapshot_available:
|
|
unpriced_seats += 1
|
|
continue
|
|
|
|
try:
|
|
await find_effective_snapshot_price_rule(
|
|
scheme_version_id=scheme_version_id,
|
|
seat_id=seat.seat_id,
|
|
group_id=seat.group_id,
|
|
sector_id=seat.sector_id,
|
|
)
|
|
priced_seats += 1
|
|
except Exception:
|
|
unpriced_seats += 1
|
|
|
|
total_seats = len(seats)
|
|
coverage_percent = round((priced_seats / total_seats) * 100, 2) if total_seats else 0.0
|
|
|
|
validation_publishable = bool(validation["summary"]["is_publishable"])
|
|
full_pricing_coverage = unpriced_seats == 0
|
|
pricing_gate_passed = full_pricing_coverage if require_full_pricing_coverage else True
|
|
|
|
is_ready_to_publish = (
|
|
validation_publishable
|
|
and snapshot_available
|
|
and pricing_gate_passed
|
|
)
|
|
|
|
return {
|
|
"validation_summary": validation["summary"],
|
|
"pricing_coverage": {
|
|
"total_seats": total_seats,
|
|
"priced_seats": priced_seats,
|
|
"unpriced_seats": unpriced_seats,
|
|
"coverage_percent": coverage_percent,
|
|
},
|
|
"snapshot": {
|
|
"available": snapshot_available,
|
|
"categories_count": len(snapshot_categories),
|
|
"rules_count": len(snapshot_rules),
|
|
},
|
|
"readiness": {
|
|
"validation_publishable": validation_publishable,
|
|
"snapshot_available": snapshot_available,
|
|
"require_full_pricing_coverage": require_full_pricing_coverage,
|
|
"full_pricing_coverage": full_pricing_coverage,
|
|
"pricing_gate_passed": pricing_gate_passed,
|
|
"is_ready_to_publish": is_ready_to_publish,
|
|
},
|
|
}
|