feat(backend): move product pricing to async persisted jobs
This commit is contained in:
parent
c869f88db2
commit
0e439b4ca7
18 changed files with 468 additions and 67 deletions
|
|
@ -1,8 +1,10 @@
|
|||
import uuid
|
||||
|
||||
from innercontext.api import products as products_api
|
||||
from innercontext.models import Product
|
||||
from innercontext.models import PricingRecalcJob, Product
|
||||
from innercontext.models.enums import DayTime, ProductCategory
|
||||
from innercontext.services.pricing_jobs import process_one_pending_pricing_job
|
||||
from sqlmodel import select
|
||||
|
||||
|
||||
def _product(
|
||||
|
|
@ -45,7 +47,7 @@ def test_compute_pricing_outputs_groups_by_category(monkeypatch):
|
|||
assert cleanser_tiers[-1] == "luxury"
|
||||
|
||||
|
||||
def test_price_tier_is_null_when_not_enough_products(client, monkeypatch):
|
||||
def test_price_tier_is_null_when_not_enough_products(client, session, monkeypatch):
|
||||
monkeypatch.setattr(products_api, "convert_to_pln", lambda amount, currency: amount)
|
||||
|
||||
base = {
|
||||
|
|
@ -67,13 +69,15 @@ def test_price_tier_is_null_when_not_enough_products(client, monkeypatch):
|
|||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
assert process_one_pending_pricing_job(session)
|
||||
|
||||
products = client.get("/products").json()
|
||||
assert len(products) == 7
|
||||
assert all(p["price_tier"] is None for p in products)
|
||||
assert all(p["price_per_use_pln"] is not None for p in products)
|
||||
|
||||
|
||||
def test_price_tier_is_computed_on_list(client, monkeypatch):
|
||||
def test_price_tier_is_computed_by_worker(client, session, monkeypatch):
|
||||
monkeypatch.setattr(products_api, "convert_to_pln", lambda amount, currency: amount)
|
||||
|
||||
base = {
|
||||
|
|
@ -91,13 +95,15 @@ def test_price_tier_is_computed_on_list(client, monkeypatch):
|
|||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
assert process_one_pending_pricing_job(session)
|
||||
|
||||
products = client.get("/products").json()
|
||||
assert len(products) == 8
|
||||
assert any(p["price_tier"] == "budget" for p in products)
|
||||
assert any(p["price_tier"] == "luxury" for p in products)
|
||||
|
||||
|
||||
def test_price_tier_uses_fallback_for_medium_categories(client, monkeypatch):
|
||||
def test_price_tier_uses_fallback_for_medium_categories(client, session, monkeypatch):
|
||||
monkeypatch.setattr(products_api, "convert_to_pln", lambda amount, currency: amount)
|
||||
|
||||
serum_base = {
|
||||
|
|
@ -130,6 +136,8 @@ def test_price_tier_uses_fallback_for_medium_categories(client, monkeypatch):
|
|||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
assert process_one_pending_pricing_job(session)
|
||||
|
||||
products = client.get("/products?category=toner").json()
|
||||
assert len(products) == 5
|
||||
assert all(p["price_tier"] is not None for p in products)
|
||||
|
|
@ -137,7 +145,7 @@ def test_price_tier_uses_fallback_for_medium_categories(client, monkeypatch):
|
|||
|
||||
|
||||
def test_price_tier_stays_null_for_tiny_categories_even_with_fallback_pool(
|
||||
client, monkeypatch
|
||||
client, session, monkeypatch
|
||||
):
|
||||
monkeypatch.setattr(products_api, "convert_to_pln", lambda amount, currency: amount)
|
||||
|
||||
|
|
@ -171,7 +179,27 @@ def test_price_tier_stays_null_for_tiny_categories_even_with_fallback_pool(
|
|||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
assert process_one_pending_pricing_job(session)
|
||||
|
||||
oils = client.get("/products?category=oil").json()
|
||||
assert len(oils) == 3
|
||||
assert all(p["price_tier"] is None for p in oils)
|
||||
assert all(p["price_tier_source"] == "insufficient_data" for p in oils)
|
||||
|
||||
|
||||
def test_product_write_enqueues_pricing_job(client, session):
|
||||
response = client.post(
|
||||
"/products",
|
||||
json={
|
||||
"name": "Serum X",
|
||||
"brand": "B",
|
||||
"category": "serum",
|
||||
"recommended_time": "both",
|
||||
"leave_on": True,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 201
|
||||
|
||||
jobs = session.exec(select(PricingRecalcJob)).all()
|
||||
assert len(jobs) == 1
|
||||
assert jobs[0].status in {"pending", "running", "succeeded"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue