This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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: ...
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user