from decimal import Decimal from app.domain.enums import Classification, Eligibility from app.domain.models import ScoringModel from app.scoring.mathutil import clamp def classify_deal_score(score: Decimal, model: ScoringModel) -> str: for bound in model.classification_upper_bounds: if bound.inclusive and score <= bound.upper: return bound.label if not bound.inclusive and score < bound.upper: return bound.label return Classification.EXCEPTIONAL.value def score_deal(product_score: Decimal, price_score: Decimal, model: ScoringModel) -> Decimal: return clamp(model.product_weight * product_score + model.price_weight * price_score) def eligibility_from_parts(product: Eligibility, offer: Eligibility) -> Eligibility: if Eligibility.INELIGIBLE in {product, offer}: return Eligibility.INELIGIBLE if Eligibility.UNKNOWN in {product, offer}: return Eligibility.UNKNOWN return Eligibility.ELIGIBLE def derive_eligible(overall: Eligibility) -> bool | None: if overall == Eligibility.ELIGIBLE: return True if overall == Eligibility.INELIGIBLE: return False return None def classification_for(overall: Eligibility, deal_score: Decimal | None, model: ScoringModel) -> str: if overall == Eligibility.INELIGIBLE: return Classification.INELIGIBLE.value if overall == Eligibility.UNKNOWN or deal_score is None: return Classification.INSUFFICIENT_DATA.value return classify_deal_score(deal_score, model)