Main Files

Core orchestration, data loading, shared models, and order history.

service.py

Back to top ↑
from __future__ import annotations

from datetime import date

from .data_loader import ReferenceData, load_reference_data
from .discount import DiscountCalculator
from .dog_age import DogAgeCalculator
from .dosage import DosageCalculator
from .medicine_cost import MedicineCostCalculator
from .models import CheckoutRequest, OrderQuote
from .order_history import OrderHistory
from .shipping import ShippingCalculator
from .tax import TaxCalculator
from .total import TotalCostCalculator

ML_PER_FL_OZ = 29.5735295625


class CheckoutService:
    def __init__(
        self,
        data: ReferenceData | None = None,
        history: OrderHistory | None = None,
    ) -> None:
        data = data or load_reference_data()
        self.history = history or OrderHistory()
        self.age = DogAgeCalculator()
        self.dosage = DosageCalculator(data.breed_base)
        self.medicine_cost = MedicineCostCalculator()
        self.discount = DiscountCalculator()
        self.shipping = ShippingCalculator(data.shipping_fee)
        self.tax = TaxCalculator(data.tax_rate_percent)
        self.total = TotalCostCalculator()
        self._us_destinations = data.us_destinations

    def checkout(self, request: CheckoutRequest) -> OrderQuote:
        self._validate_request(request)

        if self.history.has_order_within_30_days(request.owner_id, request.purchase_date):
            raise ValueError("owner already ordered a dose within the previous 30 days")

        dog_age_display = self.age.calculate(request.dog_age_years)
        dosage_ml = self.dosage.calculate_ml(
            request.dog_breed, request.dog_age_years, request.dog_weight_kg
        )
        medicine_cost = self.medicine_cost.calculate(dosage_ml)
        net_cost = self.discount.calculate(
            medicine_cost,
            request.coupons,
            request.owner_id,
            request.purchase_date,
            self.history,
        )
        discount_amount = medicine_cost - net_cost
        shipping_cost = self.shipping.calculate(request.delivery_location)
        tax_amount = self.tax.calculate(net_cost, request.delivery_location)
        total_cost = self.total.calculate(net_cost, shipping_cost, tax_amount)

        if request.delivery_location in self._us_destinations:
            dosage_display_value = dosage_ml / ML_PER_FL_OZ
            dosage_display_unit = "fl oz"
        else:
            dosage_display_value = dosage_ml
            dosage_display_unit = "mL"

        self.history.record(
            owner_id=request.owner_id,
            net_cost=net_cost,
            tax_amount=tax_amount,
            shipping_cost=shipping_cost,
            purchase_date=request.purchase_date,
            coupons=request.coupons,
        )

        return OrderQuote(
            dog_age_display=dog_age_display,
            dosage_ml=dosage_ml,
            dosage_display_value=dosage_display_value,
            dosage_display_unit=dosage_display_unit,
            medicine_cost=medicine_cost,
            discount_amount=discount_amount,
            net_cost=net_cost,
            shipping_cost=shipping_cost,
            tax_amount=tax_amount,
            total_cost=total_cost,
        )

    @staticmethod
    def _validate_request(request: CheckoutRequest) -> None:
        if not request.owner_id.strip():
            raise ValueError("owner_id is required")
        if not request.owner_location.strip():
            raise ValueError("owner_location is required")
        if not request.delivery_location.strip():
            raise ValueError("delivery_location is required")
        if not request.dog_breed.strip():
            raise ValueError("dog_breed is required")
        if not isinstance(request.purchase_date, date):
            raise ValueError("purchase_date must be a date")

data_loader.py

Back to top ↑
from __future__ import annotations

import csv
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class ReferenceData:
    breed_base: dict[str, float]
    tax_rate_percent: dict[str, float]
    shipping_fee: dict[str, float]


def load_breed_base(path: str | Path) -> dict[str, float]:
    breed_base = {}

    with open(path, newline="", encoding="utf-8") as file:
        reader = csv.DictReader(file)

        for row in reader:
            breed = row["breed"]
            dosage = float(row["base_dosage"])
            breed_base[breed] = dosage

    return breed_base


def load_location_rates(
    path: str | Path,
) -> tuple[dict[str, float], dict[str, float]]:
    tax_rates = {}
    shipping_fees = {}

    with open(path, newline="", encoding="utf-8") as file:
        reader = csv.DictReader(file)

        for row in reader:
            location = row["location"]
            tax_rate = float(row["tax_rate"])
            shipping_fee = float(row["shipping_fee"])

            # Fix the malformed row in the provided data.
            if location == "PennsylvaniaRhode Island":
                tax_rates["Pennsylvania"] = tax_rate
                tax_rates["Rhode Island"] = tax_rate

                shipping_fees["Pennsylvania"] = shipping_fee
                shipping_fees["Rhode Island"] = shipping_fee
            else:
                tax_rates[location] = tax_rate
                shipping_fees[location] = shipping_fee

    return tax_rates, shipping_fees


def load_reference_data(
    data_dir: str | Path = "data",
) -> ReferenceData:
    data_dir = Path(data_dir)

    breed_base = load_breed_base(
        data_dir / "breed_base.csv"
    )

    tax_rates, shipping_fees = load_location_rates(
        data_dir / "location_rates.csv"
    )

    return ReferenceData(
        breed_base,
        tax_rates,
        shipping_fees,
    )

models.py

Back to top ↑
from __future__ import annotations

from dataclasses import dataclass
from datetime import date


@dataclass(frozen=True)
class CheckoutRequest:
    owner_id: str
    owner_location: str
    delivery_location: str
    dog_breed: str
    dog_age_years: float
    dog_weight_kg: float
    coupons: tuple[str, ...]
    purchase_date: date


@dataclass(frozen=True)
class OrderQuote:
    dog_age_display: float
    dosage_ml: float
    dosage_display_value: float
    dosage_display_unit: str
    medicine_cost: float
    discount_amount: float
    net_cost: float
    shipping_cost: float
    tax_amount: float
    total_cost: float

order_history.py

Back to top ↑
from __future__ import annotations

from dataclasses import dataclass
from datetime import date


@dataclass(frozen=True)
class HistoryRecord:
    owner_id: str
    net_cost: float
    tax_amount: float
    shipping_cost: float
    purchase_date: date
    coupons: tuple[str, ...]


class OrderHistory:
    def __init__(self) -> None:
        self._records: list[HistoryRecord] = []

    def has_order_within_30_days(self, owner_id: str, purchase_date: date) -> bool:
        for record in self._records:
            if record.owner_id != owner_id:
                continue
            days = (purchase_date - record.purchase_date).days
            if 0 <= days < 30:
                return True
        return False

    def coupon_used_in_calendar_month(
        self, owner_id: str, coupon: str, purchase_date: date
    ) -> bool:
        return any(
            record.owner_id == owner_id
            and coupon in record.coupons
            and record.purchase_date.year == purchase_date.year
            and record.purchase_date.month == purchase_date.month
            for record in self._records
        )

    def record(
        self,
        owner_id: str,
        net_cost: float,
        tax_amount: float,
        shipping_cost: float,
        purchase_date: date,
        coupons: tuple[str, ...],
    ) -> None:
        self._records.append(
            HistoryRecord(
                owner_id=owner_id,
                net_cost=net_cost,
                tax_amount=tax_amount,
                shipping_cost=shipping_cost,
                purchase_date=purchase_date,
                coupons=tuple(coupons),
            )
        )

    def all_records(self) -> tuple[HistoryRecord, ...]:
        return tuple(self._records)

Smaller Files

Focused calculator and supporting modules.

dog_age.py

Back to top ↑
import math


class DogAgeCalculator:
    """For this fictional release, dog years = human years * 7."""

    def calculate(self, human_age_years: float) -> float:
        if not math.isfinite(human_age_years) or human_age_years < 0:
            raise ValueError("dog age must be a finite, nonnegative number")
        return human_age_years * 7.0

dosage.py

Back to top ↑
from __future__ import annotations

import math
from collections.abc import Mapping


class DosageCalculator:
    def __init__(self, breed_base: Mapping[str, float]):
        self._breed_base = dict(breed_base)

    def calculate_ml(self, breed: str, human_age_years: float, weight_kg: float) -> float:
        if breed not in self._breed_base:
            raise ValueError(f"unknown breed: {breed}")
        if not math.isfinite(human_age_years) or human_age_years < 0:
            raise ValueError("dog age must be a finite, nonnegative number")
        if not math.isfinite(weight_kg) or weight_kg <= 0:
            raise ValueError("dog weight must be a finite, positive number")

        base = self._breed_base[breed]
        dosage_ml = base * ((weight_kg + 5.0) - human_age_years / 3.0)
        if dosage_ml < 0:
            raise ValueError("the dosage formula produced a negative dosage")
        return dosage_ml

medicine_cost.py

Back to top ↑
import math


class MedicineCostCalculator:
    PRICE_PER_ML = 0.033814057

    def calculate(self, dosage_ml: float) -> float:
        if not math.isfinite(dosage_ml) or dosage_ml < 0:
            raise ValueError("dosage must be a finite, nonnegative number")
        return dosage_ml * self.PRICE_PER_ML

discount.py

Back to top ↑
from __future__ import annotations

import math
from datetime import date
from collections.abc import Sequence

from .order_history import OrderHistory


class DiscountCalculator:
    VALID_COUPONS = frozenset({"10% Off", "$10 Off", "BOGO"})

    def calculate(
        self,
        medicine_cost: float,
        coupons: Sequence[str],
        owner_id: str,
        purchase_date: date,
        history: OrderHistory,
    ) -> float:
        if not math.isfinite(medicine_cost) or medicine_cost < 0:
            raise ValueError("medicine cost must be a finite, nonnegative number")
        if len(coupons) > 2:
            raise ValueError("maximum of two coupons per transaction")
        if len(set(coupons)) != len(coupons):
            raise ValueError("a coupon type may only be used once per calendar month")

        net = medicine_cost
        for coupon in coupons:
            if coupon not in self.VALID_COUPONS:
                raise ValueError(f"unknown coupon: {coupon}")
            if coupon == "BOGO":
                raise ValueError("BOGO is unavailable in this release")
            if history.coupon_used_in_calendar_month(owner_id, coupon, purchase_date):
                raise ValueError("coupon already used this calendar month")

            # Product decision: coupons are applied sequentially in submitted order.
            if coupon == "10% Off":
                net *= 0.90
            elif coupon == "$10 Off":
                net = max(0.0, net - 10.0)

        return net

shipping.py

Back to top ↑
from __future__ import annotations

from collections.abc import Mapping


class ShippingCalculator:
    def __init__(self, shipping_fees: Mapping[str, float]):
        self._shipping_fees = dict(shipping_fees)

    def calculate(self, delivery_location: str) -> float:
        try:
            return self._shipping_fees[delivery_location]
        except KeyError as exc:
            raise ValueError(f"unsupported delivery location: {delivery_location}") from exc
from __future__ import annotations

import math
from collections.abc import Mapping


class TaxCalculator:
    def __init__(self, tax_rate_percent: Mapping[str, float]):
        self._tax_rate_percent = dict(tax_rate_percent)

    def calculate(self, net_cost: float, delivery_location: str) -> float:
        if not math.isfinite(net_cost) or net_cost < 0:
            raise ValueError("net cost must be a finite, nonnegative number")
        try:
            rate_percent = self._tax_rate_percent[delivery_location]
        except KeyError as exc:
            raise ValueError(f"unsupported delivery location: {delivery_location}") from exc
        return net_cost * rate_percent / 100.0

total.py

Back to top ↑
import math


class TotalCostCalculator:
    def calculate(self, net_cost: float, shipping_cost: float, tax_amount: float) -> float:
        values = (net_cost, shipping_cost, tax_amount)
        if any(not math.isfinite(value) or value < 0 for value in values):
            raise ValueError("total inputs must be finite and nonnegative")
        return net_cost + shipping_cost + tax_amount

Test Files

Integration and unit test modules.

test_integration.py

Back to top ↑
from __future__ import annotations

import sys
from datetime import date
from pathlib import Path
import unittest

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))

from parvocure.data_loader import load_reference_data
from parvocure.models import CheckoutRequest
from parvocure.order_history import OrderHistory
from parvocure.service import CheckoutService


DATA = load_reference_data(ROOT / "data")


class CheckoutIntegrationTests(unittest.TestCase):
    def test_us_end_to_end(self):
        service = CheckoutService(DATA)
        quote = service.checkout(
            CheckoutRequest(
                owner_id="owner-1",
                owner_location="Canada",
                delivery_location="California",
                dog_breed="Labrador Retriever",
                dog_age_years=2,
                dog_weight_kg=20,
                coupons=("10% Off",),
                purchase_date=date(2026, 3, 10),
            )
        )
        self.assertAlmostEqual(quote.dosage_ml, 37.96)
        self.assertEqual(quote.dosage_display_unit, "fl oz")
        self.assertAlmostEqual(quote.net_cost, 1.1552234433480002)
        self.assertAlmostEqual(quote.total_cost, 6.811912969633067)

    def test_non_us_uses_ml_and_delivery_location(self):
        service = CheckoutService(DATA)
        quote = service.checkout(
            CheckoutRequest(
                owner_id="owner-2",
                owner_location="California",
                delivery_location="Canada",
                dog_breed="Beagle",
                dog_age_years=4,
                dog_weight_kg=10,
                coupons=(),
                purchase_date=date(2026, 4, 1),
            )
        )
        self.assertEqual(quote.dosage_display_unit, "mL")
        self.assertAlmostEqual(quote.dosage_display_value, quote.dosage_ml)
        self.assertAlmostEqual(quote.shipping_cost, 15.5901966)
        self.assertGreater(quote.tax_amount, 0)

    def test_order_limit_and_coupon_history_cross_components(self):
        history = OrderHistory()
        service = CheckoutService(DATA, history)
        first = CheckoutRequest(
            "owner-3",
            "California",
            "Utah",
            "Poodle",
            3,
            12,
            ("10% Off",),
            date(2026, 5, 1),
        )
        service.checkout(first)

        with self.assertRaises(ValueError):
            service.checkout(
                CheckoutRequest(
                    "owner-3",
                    "California",
                    "Utah",
                    "Poodle",
                    3,
                    12,
                    (),
                    date(2026, 5, 20),
                )
            )

        # Exactly 30 days later is allowed by the dose rule, but the same coupon
        # is still in the same calendar month here only if the month matches.
        quote = service.checkout(
            CheckoutRequest(
                "owner-3",
                "California",
                "Utah",
                "Poodle",
                3,
                12,
                ("$10 Off",),
                date(2026, 5, 31),
            )
        )
        self.assertEqual(quote.tax_amount, 0.0)


if __name__ == "__main__":
    unittest.main()

test_unit.py

Back to top ↑
from __future__ import annotations

import sys
from datetime import date
from pathlib import Path
import unittest

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))

from parvocure.data_loader import load_reference_data
from parvocure.discount import DiscountCalculator
from parvocure.dog_age import DogAgeCalculator
from parvocure.dosage import DosageCalculator
from parvocure.medicine_cost import MedicineCostCalculator
from parvocure.order_history import OrderHistory
from parvocure.shipping import ShippingCalculator
from parvocure.tax import TaxCalculator
from parvocure.total import TotalCostCalculator


DATA = load_reference_data(ROOT / "data")


class DogAgeTests(unittest.TestCase):
    def test_fractional_age(self):
        self.assertAlmostEqual(DogAgeCalculator().calculate(2.5), 17.5)

    def test_negative_age_rejected(self):
        with self.assertRaises(ValueError):
            DogAgeCalculator().calculate(-0.1)


class DosageTests(unittest.TestCase):
    def setUp(self):
        self.calc = DosageCalculator(DATA.breed_base)

    def test_formula_uses_human_age(self):
        self.assertAlmostEqual(
            self.calc.calculate_ml("Labrador Retriever", 2, 20), 37.96
        )
        self.assertNotEqual(
            self.calc.calculate_ml("Labrador Retriever", 2, 20),
            self.calc.calculate_ml("Labrador Retriever", 5, 20),
        )

    def test_unknown_breed_rejected(self):
        with self.assertRaises(ValueError):
            self.calc.calculate_ml("Definitely Not A Breed", 2, 20)


class MedicineCostTests(unittest.TestCase):
    def test_price_per_ml(self):
        self.assertAlmostEqual(MedicineCostCalculator().calculate(100), 3.3814057)

    def test_negative_dosage_rejected(self):
        with self.assertRaises(ValueError):
            MedicineCostCalculator().calculate(-1)


class DiscountTests(unittest.TestCase):
    def setUp(self):
        self.calc = DiscountCalculator()
        self.history = OrderHistory()

    def test_coupons_are_sequential(self):
        first_ten_then_percent = self.calc.calculate(
            100, ("$10 Off", "10% Off"), "A", date(2026, 3, 2), self.history
        )
        percent_then_ten = self.calc.calculate(
            100, ("10% Off", "$10 Off"), "B", date(2026, 3, 2), self.history
        )
        self.assertAlmostEqual(first_ten_then_percent, 81)
        self.assertAlmostEqual(percent_then_ten, 80)

    def test_coupon_reuse_is_calendar_month(self):
        self.history.record("A", 90, 0, 5, date(2026, 1, 2), ("10% Off",))
        with self.assertRaises(ValueError):
            self.calc.calculate(
                100, ("10% Off",), "A", date(2026, 1, 31), self.history
            )
        self.assertAlmostEqual(
            self.calc.calculate(
                100, ("10% Off",), "A", date(2026, 2, 1), self.history
            ),
            90,
        )

    def test_bogo_and_duplicate_coupon_are_rejected(self):
        with self.assertRaises(ValueError):
            self.calc.calculate(100, ("BOGO",), "A", date(2026, 2, 1), self.history)
        with self.assertRaises(ValueError):
            self.calc.calculate(
                100,
                ("10% Off", "10% Off"),
                "A",
                date(2026, 2, 1),
                self.history,
            )


class ShippingTests(unittest.TestCase):
    def setUp(self):
        self.calc = ShippingCalculator(DATA.shipping_fee)

    def test_shipping_is_fee_only(self):
        self.assertAlmostEqual(self.calc.calculate("Utah"), 5.44925658)

    def test_combined_row_is_split(self):
        self.assertAlmostEqual(
            self.calc.calculate("Pennsylvania"), self.calc.calculate("Rhode Island")
        )


class TaxTests(unittest.TestCase):
    def setUp(self):
        self.calc = TaxCalculator(DATA.tax_rate_percent)

    def test_table_value_is_percent(self):
        self.assertAlmostEqual(self.calc.calculate(100, "California"), 5.59208841)

    def test_zero_tax_is_valid(self):
        self.assertEqual(self.calc.calculate(12.34, "Utah"), 0.0)


class TotalTests(unittest.TestCase):
    def test_total_includes_shipping(self):
        self.assertAlmostEqual(TotalCostCalculator().calculate(10, 5, 1), 16)

    def test_no_internal_rounding(self):
        self.assertAlmostEqual(
            TotalCostCalculator().calculate(1.111, 2.222, 3.333), 6.666
        )


class OrderHistoryTests(unittest.TestCase):
    def test_rolling_30_day_boundary(self):
        history = OrderHistory()
        history.record("A", 10, 1, 5, date(2026, 1, 15), ())
        self.assertTrue(history.has_order_within_30_days("A", date(2026, 2, 10)))
        self.assertFalse(history.has_order_within_30_days("A", date(2026, 2, 14)))

    def test_persists_required_cost_fields(self):
        history = OrderHistory()
        history.record("A", 10.5, 1.2, 5.3, date(2026, 1, 15), ("10% Off",))
        record = history.all_records()[0]
        self.assertEqual(record.owner_id, "A")
        self.assertEqual(record.net_cost, 10.5)
        self.assertEqual(record.tax_amount, 1.2)
        self.assertEqual(record.shipping_cost, 5.3)
        self.assertEqual(record.purchase_date, date(2026, 1, 15))


if __name__ == "__main__":
    unittest.main()