From 0504cc1a1e45d37e63cbfb7694e01c454a26b61b Mon Sep 17 00:00:00 2001 From: h7x4 Date: Tue, 9 Dec 2025 15:17:52 +0900 Subject: [PATCH] fixup! WIP --- dibbler/queries/product_price.py | 5 ++++ dibbler/queries/product_stock.py | 5 ++++ dibbler/queries/user_balance.py | 4 +++ tests/models/test_transaction.py | 24 --------------- tests/queries/test_joint_buy_product.py | 9 ++++++ tests/queries/test_product_price.py | 37 ++++++++++++++--------- tests/queries/test_product_stock.py | 39 ++++++++++++++++++++++++- 7 files changed, 85 insertions(+), 38 deletions(-) diff --git a/dibbler/queries/product_price.py b/dibbler/queries/product_price.py index 32e7e6e..0b3d8bc 100644 --- a/dibbler/queries/product_price.py +++ b/dibbler/queries/product_price.py @@ -63,6 +63,7 @@ def _product_price_query( TransactionType.BUY_PRODUCT, TransactionType.ADD_PRODUCT, TransactionType.ADJUST_STOCK, + TransactionType.JOINT, ] ), Transaction.product_id == product_id, @@ -117,6 +118,10 @@ def _product_price_query( trx_subset.c.type_ == TransactionType.BUY_PRODUCT, recursive_cte.c.product_count - trx_subset.c.product_count, ), + ( + trx_subset.c.type_ == TransactionType.JOINT, + recursive_cte.c.product_count - trx_subset.c.product_count, + ), # Someone adds the product -> product count is increased. ( trx_subset.c.type_ == TransactionType.ADD_PRODUCT, diff --git a/dibbler/queries/product_stock.py b/dibbler/queries/product_stock.py index cf5ce6c..fb7aa4a 100644 --- a/dibbler/queries/product_stock.py +++ b/dibbler/queries/product_stock.py @@ -37,6 +37,10 @@ def _product_stock_query( Transaction.type_ == TransactionType.ADJUST_STOCK, Transaction.product_count, ), + ( + Transaction.type_ == TransactionType.JOINT, + -Transaction.product_count, + ), else_=0, ) ) @@ -46,6 +50,7 @@ def _product_stock_query( TransactionType.BUY_PRODUCT, TransactionType.ADD_PRODUCT, TransactionType.ADJUST_STOCK, + TransactionType.JOINT, ] ), Transaction.product_id == product_id, diff --git a/dibbler/queries/user_balance.py b/dibbler/queries/user_balance.py index 3e191f3..f150f66 100644 --- a/dibbler/queries/user_balance.py +++ b/dibbler/queries/user_balance.py @@ -80,6 +80,10 @@ def _user_balance_query( TransactionType.ADJUST_BALANCE, TransactionType.BUY_PRODUCT, TransactionType.TRANSFER, + + # TODO: join this with the JOINT transactions, and determine + # how much the current user paid for the product. + TransactionType.JOINT_BUY_PRODUCT, ] ), ), diff --git a/tests/models/test_transaction.py b/tests/models/test_transaction.py index 2f5ed79..dc0c55b 100644 --- a/tests/models/test_transaction.py +++ b/tests/models/test_transaction.py @@ -19,30 +19,6 @@ def insert_test_data(sql_session: Session) -> tuple[User, Product]: return user, product -def test_transaction_no_duplicate_timestamps(sql_session: Session): - user, _ = insert_test_data(sql_session) - - transaction1 = Transaction.adjust_balance( - time=datetime(2023, 10, 1, 12, 0, 0), - user_id=user.id, - amount=100, - ) - - sql_session.add(transaction1) - sql_session.commit() - - transaction2 = Transaction.adjust_balance( - time=transaction1.time, - user_id=user.id, - amount=-50, - ) - - sql_session.add(transaction2) - - with pytest.raises(IntegrityError): - sql_session.commit() - - def test_user_not_allowed_to_transfer_to_self(sql_session: Session) -> None: user, _ = insert_test_data(sql_session) diff --git a/tests/queries/test_joint_buy_product.py b/tests/queries/test_joint_buy_product.py index e69de29..8f753ed 100644 --- a/tests/queries/test_joint_buy_product.py +++ b/tests/queries/test_joint_buy_product.py @@ -0,0 +1,9 @@ +from sqlalchemy.orm import Session + + +def test_joint_buy_product_missing_product(sql_session: Session) -> None: ... +def test_joint_buy_product_missing_user(sql_session: Session) -> None: ... +def test_joint_buy_product_out_of_stock(sql_session: Session) -> None: ... +def test_joint_buy_product(sql_session: Session) -> None: ... +def test_joint_buy_product_duplicate_user(sql_session: Session) -> None: ... +def test_joint_buy_product_non_involved_instigator(sql_session: Session) -> None: ... diff --git a/tests/queries/test_product_price.py b/tests/queries/test_product_price.py index 51c121b..736fbe2 100644 --- a/tests/queries/test_product_price.py +++ b/tests/queries/test_product_price.py @@ -5,7 +5,7 @@ from pprint import pprint from sqlalchemy.orm import Session from dibbler.models import Product, Transaction, User -from dibbler.queries import product_price, product_price_log +from dibbler.queries import product_price, product_price_log, joint_buy_product # TODO: see if we can use pytest_runtest_makereport to print the "product_price_log"s # only on failures instead of inlining it in every test function @@ -367,21 +367,27 @@ def test_product_price_joint_transactions(sql_session: Session) -> None: ), ] - transactions += Transaction.buy_joint_product( - time=datetime(2023, 10, 1, 12, 0, 2), - product_count=2, - user_ids=[user1.id, user2.id], - product_id=product.id, - ) - sql_session.add_all(transactions) sql_session.commit() - pprint(product_price_log(sql_session, product)) - product_price_ = product_price(sql_session, product) assert product_price_ == math.ceil((30 * 3 + 20 * 2) / (3 + 2)) + joint_buy_product( + sql_session, + time=datetime(2023, 10, 1, 12, 0, 2), + instigator=user1, + users=[user1, user2], + product=product, + product_count=2, + ) + + pprint(product_price_log(sql_session, product)) + + old_product_price = product_price_ + product_price_ = product_price(sql_session, product) + assert product_price_ == old_product_price, "Joint buy transactions should not affect product price" + transactions = [ Transaction.add_product( time=datetime(2023, 10, 1, 12, 0, 3), @@ -399,7 +405,12 @@ def test_product_price_joint_transactions(sql_session: Session) -> None: pprint(product_price_log(sql_session, product)) product_price_ = product_price(sql_session, product) - expected_product_price = (30 * 3 + 20 * 2) / (3 + 2) - expected_product_price = (expected_product_price * (3 + 2) + 25 * 4) / (3 + 4) + # Expected state: + # Added products: + # Count: 3 + 2 = 5, Price: (30 * 3 + 20 * 2) / 5 = 26 + # Joint bought products: + # Count: 5 - 2 = 3, Price: n/a (should not affect price) + # Added products: + # Count: 3 + 4 = 7, Price: (26 * 3 + 25 * 4) / (3 + 4) = 25.57 -> 26 - assert product_price_ == math.ceil(expected_product_price) + assert product_price_ == math.ceil((26 * 3 + 25 * 4) / (3 + 4)) diff --git a/tests/queries/test_product_stock.py b/tests/queries/test_product_stock.py index d883c23..e61c784 100644 --- a/tests/queries/test_product_stock.py +++ b/tests/queries/test_product_stock.py @@ -4,7 +4,7 @@ from sqlalchemy import select from sqlalchemy.orm import Session from dibbler.models import Product, Transaction, User -from dibbler.queries import product_stock +from dibbler.queries import product_stock, joint_buy_product def insert_test_data(sql_session: Session) -> None: @@ -139,3 +139,40 @@ def test_negative_product_stock(sql_session: Session) -> None: # The stock should be negative because we added and bought the product assert product_stock(sql_session, product) == 1 - 2 - 1 + +def test_product_stock_joint_transaction(sql_session: Session) -> None: + insert_test_data(sql_session) + + user1 = sql_session.scalars(select(User).where(User.name == "Test User 1")).one() + user2 = User("Test User 2") + sql_session.add(user2) + sql_session.commit() + + product = Product("1234567890123", "Test Product") + sql_session.add(product) + sql_session.commit() + + transactions = [ + Transaction.add_product( + time=datetime(2023, 10, 1, 17, 0, 0), + amount=100, + per_product=100, + user_id=user1.id, + product_id=product.id, + product_count=5, + ), + ] + + sql_session.add_all(transactions) + sql_session.commit() + + joint_buy_product( + sql_session, + time=datetime(2023, 10, 1, 17, 0, 1), + instigator=user1, + users=[user1, user2], + product=product, + product_count=3, + ) + + assert product_stock(sql_session, product) == 5 - 3