"""Pricing engine. Applies active `price_rules` (cost -> markup bands) and computes net profit: retail = cost * (1 + markup_pct/100) (floored at cost + shipping + fees) net profit = retail - cost - shipping - fees margin_pct = profit / retail * 100 `min_price` (product floor) is respected — retail is never below it. """ from decimal import ROUND_HALF_UP, Decimal from app.models import PriceRule CENT = Decimal("0.01") def _q(value) -> Decimal: try: return Decimal(str(value or 0)) except Exception: return Decimal("0") def get_active_rules(db): return ( db.query(PriceRule) .filter(PriceRule.active.is_(True)) .order_by(PriceRule.min_cost) .all() ) def find_rule(db, cost): cost = _q(cost) for rule in get_active_rules(db): if cost >= _q(rule.min_cost) and (rule.max_cost is None or cost < _q(rule.max_cost)): return rule return None def calculate_price(db, cost, shipping=0, fees=0, min_price=None): """Return dict(retail, profit, margin, margin_pct, markup_pct, rule_id, ...) or None. None means no active rule applies — callers must NOT publish such products. """ cost = _q(cost) shipping = _q(shipping) fees = _q(fees) rule = find_rule(db, cost) if rule is None: return None markup_pct = _q(rule.markup_pct) retail = (cost * (1 + markup_pct / 100)).quantize(CENT, rounding=ROUND_HALF_UP) # floor: cost + shipping + fees, raised by min_margin_pct if configured floor = (cost + shipping + fees).quantize(CENT, rounding=ROUND_HALF_UP) min_margin_pct = _q(rule.min_margin_pct) if min_margin_pct > 0: floor = max(floor, (floor + retail * min_margin_pct / 100).quantize(CENT, rounding=ROUND_HALF_UP)) if retail < floor: retail = floor # never below the product's minimum price if min_price is not None and retail < _q(min_price): retail = _q(min_price).quantize(CENT, rounding=ROUND_HALF_UP) profit = (retail - cost - shipping - fees).quantize(CENT, rounding=ROUND_HALF_UP) margin_pct = (profit / retail * 100).quantize(Decimal("0.01")) if retail > 0 else Decimal("0") return { "cost": cost, "shipping": shipping, "fees": fees, "retail": retail, "profit": profit, "margin": profit, "margin_pct": float(margin_pct), "markup_pct": float(markup_pct), "rule_id": rule.id, } def estimate_net_profit(retail, cost, shipping=0, fees=0): """Net profit = retail - (cost + shipping + fees).""" return (_q(retail) - _q(cost) - _q(shipping) - _q(fees)).quantize(CENT, rounding=ROUND_HALF_UP)