Spaces:
Sleeping
Sleeping
File size: 4,793 Bytes
8981bf6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | """Policy-driven return/refund decision engine.
This is the highest-stakes automation in the product, so the logic is explicit,
deterministic, and unit-tested rather than left to the language model. The LLM drafts
the customer-facing wording; *this* decides what we will actually do, with the policy
clause that justifies it.
Decision outcomes:
approve β eligible refund, possibly net of a return-shipping fee
deny β not eligible (final sale, worn, outside window, hygiene)
escalate β needs a human (e.g. claimed defect, which requires inspecting a photo)
"""
from __future__ import annotations
import re
from dataclasses import dataclass, field
from datetime import date
from .orders import Order
RETURN_WINDOW_DAYS = 30
RETURN_SHIPPING_FEE = 7.95
_DEFECT_TERMS = re.compile(
r"\b(defect|defective|broke|broken|snapped|split|tore|torn|ripped|faulty|"
r"damaged on arrival|arrived damaged|stopped working|malfunction)\b",
re.IGNORECASE,
)
_WORN_TERMS = re.compile(
r"\b(worn|used|washed|wore|after .*hike|on .*hikes|opened|mouthpiece)\b",
re.IGNORECASE,
)
@dataclass(frozen=True)
class RefundDecision:
outcome: str # "approve" | "deny" | "escalate"
refund_amount: float
reason: str
policy_citation: str
fee_applied: float = 0.0
requires_human: bool = False
notes: list[str] = field(default_factory=list)
def decide_refund(
order: Order,
message: str = "",
today: date | None = None,
our_error: bool = False,
) -> RefundDecision:
"""Decide a refund for ``order`` given the customer's ``message``.
``our_error`` marks the return as caused by us (wrong/defective item confirmed),
which waives the return-shipping fee per the Returns policy.
"""
today = today or date.today()
claims_defect = bool(_DEFECT_TERMS.search(message))
claims_worn = bool(_WORN_TERMS.search(message))
# 1) Defect claims go to warranty/human review β we don't auto-approve money on an
# unverified physical defect; a photo must be inspected.
if claims_defect:
return RefundDecision(
outcome="escalate",
refund_amount=0.0,
reason=(
"Customer reports a possible manufacturing defect. Warranty claims "
"require a human to review the photo of the defect before approval."
),
policy_citation="Warranty policy",
requires_human=True,
notes=["defect_claim"],
)
# 2) Final sale / hygiene items are never refundable.
if order.final_sale:
return RefundDecision(
outcome="deny",
refund_amount=0.0,
reason=(
"This order contains Final Sale item(s), which are not returnable or "
"refundable. A manufacturing-defect warranty claim is still possible."
),
policy_citation="Final Sale policy",
notes=["final_sale"],
)
# 3) Worn/washed/used items are not eligible for a standard refund.
if claims_worn:
return RefundDecision(
outcome="deny",
refund_amount=0.0,
reason=(
"The item is described as worn/used, which is not eligible for a "
"standard refund. Only unused items in original condition qualify."
),
policy_citation="Returns policy",
notes=["worn_or_used"],
)
# 4) Standard return window. Undelivered orders are still inside the window
# (clock starts at delivery), so treat "not yet delivered" as eligible.
days = order.days_since_delivery(today)
if days is not None and days > RETURN_WINDOW_DAYS:
return RefundDecision(
outcome="deny",
refund_amount=0.0,
reason=(
f"This order was delivered {days} days ago, beyond the "
f"{RETURN_WINDOW_DAYS}-day return window."
),
policy_citation="Returns policy",
notes=["outside_window"],
)
# 5) Eligible standard refund. Apply the return-shipping fee unless it's our error.
fee = 0.0 if our_error else RETURN_SHIPPING_FEE
refund = round(max(order.total - fee, 0.0), 2)
reason = (
"Unused item within the 30-day return window β eligible for a refund to the "
"original payment method."
)
if fee:
reason += f" A ${fee:.2f} return-shipping fee applies."
else:
reason += " Return shipping is free because the return is due to our error."
return RefundDecision(
outcome="approve",
refund_amount=refund,
reason=reason,
policy_citation="Returns policy",
fee_applied=fee,
notes=["standard_refund"],
)
|