70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
"""Unit tests for the price-verdict logic (pure, no network)."""
|
|
from __future__ import annotations
|
|
|
|
from config.settings import PricingRules
|
|
from pricing_agent.analyze import Rating, classify_trend, price_verdict, suggested_price
|
|
from pricing_agent.tools.margin_engine import stack_from_quote
|
|
from pricing_agent.schemas import FeeQuote
|
|
|
|
RULES = PricingRules(margin_floor=0.25, margin_target=0.30)
|
|
|
|
|
|
def test_suggested_price_clears_target_margin():
|
|
# Real pillow fee model: landed 8.59, fba 8.97, referral 15%, returns 2%, other 0.11.
|
|
quote = FeeQuote(selling_price=24.99, landed_cost=8.59, fba_fee=8.97,
|
|
referral_amt=3.75, returns_reserve=0.50, other_fees=0.11,
|
|
net_takehome=3.07, source="cosmos")
|
|
stack = stack_from_quote(quote, RULES)
|
|
sug = suggested_price(stack, RULES.margin_target)
|
|
assert sug is not None
|
|
# ~$33.34 rounded up to a .99 ending.
|
|
assert 33.0 <= sug <= 34.5
|
|
assert round(sug - int(sug), 2) == 0.99
|
|
# Re-price at the suggestion and confirm it clears the 30% target.
|
|
requote = FeeQuote(selling_price=sug, landed_cost=8.59, fba_fee=8.97,
|
|
referral_amt=0.15 * sug, returns_reserve=0.02 * sug,
|
|
other_fees=0.11, source="cosmos")
|
|
restack = stack_from_quote(requote, RULES)
|
|
assert restack.contribution_margin_pct >= RULES.margin_target
|
|
|
|
|
|
def _verdict(**kw):
|
|
base = dict(trend="stable", selling=True, cover_days=60, monthly_take_home=10000.0, rules=RULES)
|
|
base.update(kw)
|
|
return price_verdict(**base)[0]
|
|
|
|
|
|
def test_trend_classification():
|
|
assert classify_trend(1714, 1655) == "stable" # ~+3.6%
|
|
assert classify_trend(2000, 1655) == "rising" # +21%
|
|
assert classify_trend(1300, 1655) == "declining" # -21%
|
|
assert classify_trend(None, 1655) == "unknown"
|
|
|
|
|
|
def test_good_price_healthy_margin_and_demand():
|
|
assert _verdict(margin_pct=0.31) == Rating.GOOD
|
|
|
|
|
|
def test_thin_margin_but_strong_demand_is_caution_raise_price():
|
|
assert _verdict(margin_pct=0.12, trend="stable", selling=True) == Rating.CAUTION
|
|
|
|
|
|
def test_thin_margin_and_weak_demand_is_poor():
|
|
assert _verdict(margin_pct=0.12, trend="declining", selling=False) == Rating.POOR
|
|
|
|
|
|
def test_negative_margin_is_poor_even_with_strong_demand():
|
|
assert _verdict(margin_pct=-0.059, trend="stable", selling=True) == Rating.POOR
|
|
|
|
|
|
def test_overstock_storage_drain_is_caution():
|
|
assert _verdict(margin_pct=0.31, cover_days=200) == Rating.CAUTION
|
|
|
|
|
|
def test_negative_monthly_takehome_is_poor():
|
|
assert _verdict(margin_pct=0.31, monthly_take_home=-2813.0) == Rating.POOR
|
|
|
|
|
|
def test_declining_demand_with_good_margin_is_caution():
|
|
assert _verdict(margin_pct=0.31, trend="declining") == Rating.CAUTION
|