From 1b9f62cc75ab78827d5bb7b3334ead3103910d18 Mon Sep 17 00:00:00 2001 From: Cecchinato Mathieu Date: Tue, 18 Mar 2025 14:33:09 +0100 Subject: [PATCH 01/15] AMAP in cents # Conflicts: # app/modules/amap/endpoints_amap.py # app/modules/amap/models_amap.py --- app/modules/amap/endpoints_amap.py | 44 ++++----- app/modules/amap/models_amap.py | 6 +- app/modules/amap/schemas_amap.py | 4 +- migrations/versions/29-price_in_cents.py | 115 +++++++++++++++++++++++ 4 files changed, 142 insertions(+), 27 deletions(-) create mode 100644 migrations/versions/29-price_in_cents.py diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index 4c9e773c06..d7406b4424 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -462,16 +462,15 @@ async def add_order_to_delievery( if not amount: raise HTTPException(status_code=400, detail="You can't order nothing") - + """ redis_key = "amap_" + order.user_id - - if not isinstance(redis_client, Redis) or locker_get( - redis_client=redis_client, - key=redis_key, - ): - raise HTTPException(status_code=429, detail="Too fast !") - locker_set(redis_client=redis_client, key=redis_key, lock=True) - + if not isinstance(redis_client, Redis) or locker_get( + redis_client=redis_client, + key=redis_key, + ): + raise HTTPException(status_code=429, detail="Too fast !") + locker_set(redis_client=redis_client, key=redis_key, lock=True) + """ try: await cruds_amap.add_order_to_delivery( order=db_order, @@ -494,8 +493,8 @@ async def add_order_to_delievery( except ValueError as error: raise HTTPException(status_code=400, detail=str(error)) - finally: - locker_set(redis_client=redis_client, key=redis_key, lock=False) + # finally: + # locker_set(redis_client=redis_client, key=redis_key, lock=False) @module.router.patch( @@ -584,14 +583,15 @@ async def edit_order_from_delivery( if not balance: raise HTTPException(status_code=404, detail="No cash found") + """ redis_key = "amap_" + previous_order.user_id - - if not isinstance(redis_client, Redis) or locker_get( - redis_client=redis_client, - key=redis_key, - ): - raise HTTPException(status_code=429, detail="Too fast !") - locker_set(redis_client=redis_client, key=redis_key, lock=True) + if not isinstance(redis_client, Redis) or locker_get( + redis_client=redis_client, + key=redis_key, + ): + raise HTTPException(status_code=429, detail="Too fast !") + locker_set(redis_client=redis_client, key=redis_key, lock=True) + """ try: await cruds_amap.edit_order_with_products( @@ -615,8 +615,8 @@ async def edit_order_from_delivery( except ValueError as error: raise HTTPException(status_code=400, detail=str(error)) - finally: - locker_set(redis_client=redis_client, key=redis_key, lock=False) + # finally: + # locker_set(redis_client=redis_client, key=redis_key, lock=False) @module.router.delete( @@ -878,7 +878,7 @@ async def create_cash_of_user( detail="This user already has a cash.", ) - cash_db = models_amap.Cash(user_id=user_id, balance=cash.balance) + cash_db = models_amap.Cash(user_id=user_id, balance=cash.balance, user=user) await cruds_amap.create_cash_of_user( cash=cash_db, @@ -898,7 +898,7 @@ async def create_cash_of_user( message = Message( title="AMAP - Solde mis à jour", - content=f"Votre nouveau solde est de {cash} €.", + content=f"Votre nouveau solde est de {cash.balance//100}€{cash.balance%100}.", action_module="amap", ) await notification_tool.send_notification_to_user( diff --git a/app/modules/amap/models_amap.py b/app/modules/amap/models_amap.py index 855e75d2e0..0127d2b6ce 100644 --- a/app/modules/amap/models_amap.py +++ b/app/modules/amap/models_amap.py @@ -2,7 +2,7 @@ from datetime import date, datetime -from sqlalchemy import ForeignKey, String +from sqlalchemy import ForeignKey, Integer, String from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.users.models_users import CoreUser @@ -76,7 +76,7 @@ class Order(Base): index=True, ) order_id: Mapped[str] = mapped_column(primary_key=True, index=True) - amount: Mapped[float] + amount: Mapped[int] collection_slot: Mapped[AmapSlotType] ordering_date: Mapped[datetime] delivery_date: Mapped[date] @@ -88,7 +88,7 @@ class Order(Base): "Product", secondary="amap_order_content", viewonly=True, - default_factory=list, + init=False, ) diff --git a/app/modules/amap/schemas_amap.py b/app/modules/amap/schemas_amap.py index 26224ffd51..332ba8df6c 100644 --- a/app/modules/amap/schemas_amap.py +++ b/app/modules/amap/schemas_amap.py @@ -75,7 +75,7 @@ class OrderBase(BaseModel): class OrderComplete(OrderBase): order_id: str - amount: float + amount: int ordering_date: datetime delivery_date: date model_config = ConfigDict(from_attributes=True) @@ -87,7 +87,7 @@ class OrderReturn(BaseModel): productsdetail: Sequence[ProductQuantity] collection_slot: AmapSlotType order_id: str - amount: float + amount: int ordering_date: datetime delivery_date: date model_config = ConfigDict(from_attributes=True) diff --git a/migrations/versions/29-price_in_cents.py b/migrations/versions/29-price_in_cents.py new file mode 100644 index 0000000000..53baebe28a --- /dev/null +++ b/migrations/versions/29-price_in_cents.py @@ -0,0 +1,115 @@ +"""empty message + +Create Date: 2025-02-25 13:45:05.381491 +""" + +from collections.abc import Sequence +from typing import TYPE_CHECKING, Union + +if TYPE_CHECKING: + from pytest_alembic import MigrationContext + +import sqlalchemy as sa +from alembic import op + +from app.types.sqlalchemy import TZDateTime + +# revision identifiers, used by Alembic. +revision: str = "4ae072a7e867" +down_revision: str | None = "c778706af06f" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "amap_cash", + "balance", + existing_type=sa.FLOAT(), + type_=sa.Integer(), + existing_nullable=False, + ) + op.alter_column( + "amap_order", + "amount", + existing_type=sa.FLOAT(), + type_=sa.Integer(), + existing_nullable=False, + ) + op.alter_column( + "amap_product", + "price", + existing_type=sa.FLOAT(), + type_=sa.Integer(), + existing_nullable=False, + ) + op.alter_column( + "raffle_cash", + "balance", + existing_type=sa.FLOAT(), + type_=sa.Integer(), + existing_nullable=False, + ) + op.alter_column( + "raffle_pack_ticket", + "price", + existing_type=sa.FLOAT(), + type_=sa.Integer(), + existing_nullable=False, + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "raffle_pack_ticket", + "price", + existing_type=sa.Integer(), + type_=sa.FLOAT(), + existing_nullable=False, + ) + op.alter_column( + "raffle_cash", + "balance", + existing_type=sa.Integer(), + type_=sa.FLOAT(), + existing_nullable=False, + ) + op.alter_column( + "amap_product", + "price", + existing_type=sa.Integer(), + type_=sa.FLOAT(), + existing_nullable=False, + ) + op.alter_column( + "amap_order", + "amount", + existing_type=sa.Integer(), + type_=sa.FLOAT(), + existing_nullable=False, + ) + op.alter_column( + "amap_cash", + "balance", + existing_type=sa.Integer(), + type_=sa.FLOAT(), + existing_nullable=False, + ) + # ### end Alembic commands ### + + +def pre_test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass + + +def test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass From ac2c9cce2c1ef52913bb99a0b322a8667ab26ff3 Mon Sep 17 00:00:00 2001 From: Foucauld Bellanger <63885990+Foukki@users.noreply.github.com> Date: Wed, 26 Mar 2025 11:16:06 +0100 Subject: [PATCH 02/15] migration --- app/modules/amap/models_amap.py | 4 +- app/modules/raffle/models_raffle.py | 4 +- migrations/versions/29-price_in_cents.py | 126 +++++++++++++++++++++-- 3 files changed, 121 insertions(+), 13 deletions(-) diff --git a/app/modules/amap/models_amap.py b/app/modules/amap/models_amap.py index 0127d2b6ce..4f3eee0407 100644 --- a/app/modules/amap/models_amap.py +++ b/app/modules/amap/models_amap.py @@ -44,7 +44,7 @@ class Product(Base): index=True, unique=True, ) - price: Mapped[float] + price: Mapped[int] category: Mapped[str] = mapped_column(index=True) @@ -99,7 +99,7 @@ class Cash(Base): ForeignKey("core_user.id"), primary_key=True, ) - balance: Mapped[float] + balance: Mapped[int] user: Mapped[CoreUser] = relationship("CoreUser", init=False) diff --git a/app/modules/raffle/models_raffle.py b/app/modules/raffle/models_raffle.py index 92c05a33e8..68bd193eb3 100644 --- a/app/modules/raffle/models_raffle.py +++ b/app/modules/raffle/models_raffle.py @@ -36,7 +36,7 @@ class PackTicket(Base): primary_key=True, index=True, ) - price: Mapped[float] + price: Mapped[int] pack_size: Mapped[int] raffle_id: Mapped[str] = mapped_column( ForeignKey("raffle.id"), @@ -93,6 +93,6 @@ class Cash(Base): ForeignKey("core_user.id"), primary_key=True, ) - balance: Mapped[float] + balance: Mapped[int] user: Mapped[CoreUser] = relationship("CoreUser", init=False) diff --git a/migrations/versions/29-price_in_cents.py b/migrations/versions/29-price_in_cents.py index 53baebe28a..32e0e0d254 100644 --- a/migrations/versions/29-price_in_cents.py +++ b/migrations/versions/29-price_in_cents.py @@ -4,7 +4,11 @@ """ from collections.abc import Sequence -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING +from uuid import uuid4 + +from app.core.schools.schools_type import SchoolType +from app.modules.raffle.types_raffle import RaffleStatusType if TYPE_CHECKING: from pytest_alembic import MigrationContext @@ -12,8 +16,6 @@ import sqlalchemy as sa from alembic import op -from app.types.sqlalchemy import TZDateTime - # revision identifiers, used by Alembic. revision: str = "4ae072a7e867" down_revision: str | None = "c778706af06f" @@ -22,7 +24,12 @@ def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### + op.execute("UPDATE amap_cash SET balance = balance * 100") + op.execute("UPDATE amap_order SET amount = amount * 100") + op.execute("UPDATE amap_product SET price = price * 100") + op.execute("UPDATE raffle_cash SET balance = balance * 100") + op.execute("UPDATE raffle_pack_ticket SET price = price * 100") + op.alter_column( "amap_cash", "balance", @@ -58,11 +65,15 @@ def upgrade() -> None: type_=sa.Integer(), existing_nullable=False, ) - # ### end Alembic commands ### def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### + op.execute("UPDATE amap_cash SET balance = balance / 100") + op.execute("UPDATE amap_order SET amount = amount / 100") + op.execute("UPDATE amap_product SET price = price / 100") + op.execute("UPDATE raffle_cash SET balance = balance / 100") + op.execute("UPDATE raffle_pack_ticket SET price = price / 100") + op.alter_column( "raffle_pack_ticket", "price", @@ -98,18 +109,115 @@ def downgrade() -> None: type_=sa.FLOAT(), existing_nullable=False, ) - # ### end Alembic commands ### + + +user_id = uuid4() +group_id = uuid4() +raffle_id = uuid4() def pre_test_upgrade( alembic_runner: "MigrationContext", alembic_connection: sa.Connection, ) -> None: - pass + alembic_runner.insert_into( + "core_group", + { + "id": group_id, + "name": "external", + }, + ) + + alembic_runner.insert_into( + "core_user", + { + "id": user_id, + "email": "dedftyugimo@myecl.fr", + "account_type": "external", + "school_id": SchoolType.no_school.value, + "password_hash": "password_hash", + "name": "name", + "firstname": "firstname", + "nickname": "nickname", + "birthday": None, + "promo": 21, + "phone": "phone", + "floor": "Autre", + "created_on": None, + }, + ) + alembic_runner.insert_into( + "core_membership", + { + "user_id": user_id, + "group_id": group_id, + }, + ) + alembic_runner.insert_into( + "amap_cash", + { + "user_id": user_id, + "balance": 11.56, + }, + ) + alembic_runner.insert_into( + "amap_product", + { + "id": uuid4(), + "name": "name", + "price": 10.511111, + "category": "category", + }, + ) + alembic_runner.insert_into( + "raffle_cash", + { + "user_id": user_id, + "balance": 4.99999999997, + }, + ) + alembic_runner.insert_into( + "raffle", + { + "id": raffle_id, + "name": "name", + "group_id": group_id, + "status": RaffleStatusType.creation, + }, + ) + alembic_runner.insert_into( + "raffle_pack_ticket", + { + "id": uuid4(), + "price": 7.5, + "pack_size": 5, + "raffle_id": raffle_id, + }, + ) def test_upgrade( alembic_runner: "MigrationContext", alembic_connection: sa.Connection, ) -> None: - pass + amap_cash = alembic_connection.execute( + sa.text(f"SELECT balance FROM amap_cash WHERE user_id = '{user_id}'"), + ).fetchall() + assert amap_cash[0][0] == 1156 + + amap_product = alembic_connection.execute( + sa.text("SELECT price FROM amap_product WHERE name = 'name'"), + ).fetchall() + assert amap_product[0][0] == 1051 + + raffle_cash = alembic_connection.execute( + sa.text(f"SELECT balance FROM raffle_cash WHERE user_id = '{user_id}'"), + ).fetchall() + assert raffle_cash[0][0] == 500 + + raffle_pack_ticket = alembic_connection.execute( + sa.text( + f"SELECT price FROM raffle_pack_ticket WHERE raffle_id = '{raffle_id}'", + ), + ).fetchall() + assert raffle_pack_ticket[0][0] == 750 From 403501e5310b640e884a5440363d4f83a876b17b Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 1 Apr 2025 12:22:07 +0200 Subject: [PATCH 03/15] Fix: clean up and correct migration --- app/modules/amap/models_amap.py | 2 +- migrations/versions/29-price_in_cents.py | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/app/modules/amap/models_amap.py b/app/modules/amap/models_amap.py index 4f3eee0407..9ec2434c0c 100644 --- a/app/modules/amap/models_amap.py +++ b/app/modules/amap/models_amap.py @@ -2,7 +2,7 @@ from datetime import date, datetime -from sqlalchemy import ForeignKey, Integer, String +from sqlalchemy import ForeignKey, String from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.users.models_users import CoreUser diff --git a/migrations/versions/29-price_in_cents.py b/migrations/versions/29-price_in_cents.py index 32e0e0d254..c54034c479 100644 --- a/migrations/versions/29-price_in_cents.py +++ b/migrations/versions/29-price_in_cents.py @@ -68,12 +68,6 @@ def upgrade() -> None: def downgrade() -> None: - op.execute("UPDATE amap_cash SET balance = balance / 100") - op.execute("UPDATE amap_order SET amount = amount / 100") - op.execute("UPDATE amap_product SET price = price / 100") - op.execute("UPDATE raffle_cash SET balance = balance / 100") - op.execute("UPDATE raffle_pack_ticket SET price = price / 100") - op.alter_column( "raffle_pack_ticket", "price", @@ -110,6 +104,12 @@ def downgrade() -> None: existing_nullable=False, ) + op.execute("UPDATE amap_cash SET balance = balance / 100") + op.execute("UPDATE amap_order SET amount = amount / 100") + op.execute("UPDATE amap_product SET price = price / 100") + op.execute("UPDATE raffle_cash SET balance = balance / 100") + op.execute("UPDATE raffle_pack_ticket SET price = price / 100") + user_id = uuid4() group_id = uuid4() @@ -146,13 +146,6 @@ def pre_test_upgrade( "created_on": None, }, ) - alembic_runner.insert_into( - "core_membership", - { - "user_id": user_id, - "group_id": group_id, - }, - ) alembic_runner.insert_into( "amap_cash", { From 85ef75196e72970f48b83eb6da2a89bd45f00054 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 1 Apr 2025 12:48:35 +0200 Subject: [PATCH 04/15] Fix: endpoints and tests --- app/modules/amap/endpoints_amap.py | 2 +- app/modules/amap/schemas_amap.py | 8 ++++---- app/modules/raffle/schemas_raffle.py | 10 +++++----- tests/test_amap.py | 12 ++++++------ tests/test_raffle.py | 12 ++++++------ 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index d7406b4424..8759e0a440 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -878,7 +878,7 @@ async def create_cash_of_user( detail="This user already has a cash.", ) - cash_db = models_amap.Cash(user_id=user_id, balance=cash.balance, user=user) + cash_db = models_amap.Cash(user_id=user_id, balance=cash.balance) await cruds_amap.create_cash_of_user( cash=cash_db, diff --git a/app/modules/amap/schemas_amap.py b/app/modules/amap/schemas_amap.py index 332ba8df6c..9647ec13f8 100644 --- a/app/modules/amap/schemas_amap.py +++ b/app/modules/amap/schemas_amap.py @@ -20,7 +20,7 @@ class ProductBase(BaseModel): """Base schema for AMAP products""" name: str - price: float + price: int class ProductSimple(ProductBase): @@ -30,7 +30,7 @@ class ProductSimple(ProductBase): class ProductEdit(BaseModel): category: str | None = None name: str | None = None - price: float | None = None + price: int | None = None class ProductComplete(ProductSimple): @@ -114,7 +114,7 @@ class AddProductDelivery(BaseModel): class CashBase(BaseModel): - balance: float + balance: int user_id: str model_config = ConfigDict(from_attributes=True) @@ -128,7 +128,7 @@ class CashDB(CashBase): class CashEdit(BaseModel): - balance: float + balance: int class Information(BaseModel): diff --git a/app/modules/raffle/schemas_raffle.py b/app/modules/raffle/schemas_raffle.py index 71d6d987ad..da27511a99 100644 --- a/app/modules/raffle/schemas_raffle.py +++ b/app/modules/raffle/schemas_raffle.py @@ -25,7 +25,7 @@ class RaffleComplete(RaffleBase): class RaffleStats(BaseModel): tickets_sold: int - amount_raised: float + amount_raised: int class PrizeBase(BaseModel): @@ -55,7 +55,7 @@ class PrizeComplete(PrizeBase): class PackTicketBase(BaseModel): - price: float + price: int pack_size: int raffle_id: str model_config = ConfigDict(from_attributes=True) @@ -63,7 +63,7 @@ class PackTicketBase(BaseModel): class PackTicketEdit(BaseModel): raffle_id: str | None = None - price: float | None = None + price: int | None = None pack_size: int | None = None model_config = ConfigDict(from_attributes=True) @@ -97,7 +97,7 @@ class TicketComplete(TicketSimple): class CashBase(BaseModel): - balance: float + balance: int user_id: str model_config = ConfigDict(from_attributes=True) @@ -111,4 +111,4 @@ class CashDB(CashBase): class CashEdit(BaseModel): - balance: float + balance: int diff --git a/tests/test_amap.py b/tests/test_amap.py index a7700e7eca..bd0c5881c8 100644 --- a/tests/test_amap.py +++ b/tests/test_amap.py @@ -47,14 +47,14 @@ async def init_objects() -> None: product = models_amap.Product( id=str(uuid.uuid4()), name="Tomato", - price=1.5, + price=150, category="Test", ) await add_object_to_db(product) deletable_product = models_amap.Product( id=str(uuid.uuid4()), name="Deletable Tomato", - price=1.5, + price=150, category="Test", ) await add_object_to_db(deletable_product) @@ -84,7 +84,7 @@ async def init_objects() -> None: order_id=str(uuid.uuid4()), user_id=student_user.id, delivery_id=delivery.id, - amount=0.0, + amount=0, collection_slot=AmapSlotType.midi, ordering_date=datetime(2022, 8, 10, 12, 16, 26, tzinfo=UTC), delivery_date=delivery.delivery_date, @@ -95,7 +95,7 @@ async def init_objects() -> None: order_id=str(uuid.uuid4()), user_id=student_user.id, delivery_id=locked_delivery.id, - amount=0.0, + amount=0, collection_slot=AmapSlotType.midi, ordering_date=datetime(2022, 8, 18, 12, 16, 26, tzinfo=UTC), delivery_date=locked_delivery.delivery_date, @@ -121,7 +121,7 @@ def test_create_product(client: TestClient) -> None: response = client.post( "/amap/products", - json={"name": "test", "price": 0.1, "category": "test"}, + json={"name": "test", "price": 10, "category": "test"}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 201 @@ -143,7 +143,7 @@ def test_edit_product(client: TestClient) -> None: response = client.patch( f"/amap/products/{product.id}", - json={"name": "testupdate", "price": 0.1, "category": "test"}, + json={"name": "testupdate", "price": 10, "category": "test"}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 204 diff --git a/tests/test_raffle.py b/tests/test_raffle.py index 64ab58af5d..2865da9353 100644 --- a/tests/test_raffle.py +++ b/tests/test_raffle.py @@ -83,7 +83,7 @@ async def init_objects() -> None: packticket = models_raffle.PackTicket( id=str(uuid.uuid4()), - price=1.0, + price=100, pack_size=1, raffle_id=raffle.id, ) @@ -91,7 +91,7 @@ async def init_objects() -> None: packticket_to_draw = models_raffle.PackTicket( id=str(uuid.uuid4()), - price=1.0, + price=100, pack_size=1, raffle_id=raffle_to_draw.id, ) @@ -99,7 +99,7 @@ async def init_objects() -> None: packticket_to_delete = models_raffle.PackTicket( id=str(uuid.uuid4()), - price=1.0, + price=100, pack_size=1, raffle_id=raffle_to_delete.id, ) @@ -280,7 +280,7 @@ def test_get_raffle_stats(client: TestClient) -> None: headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 - assert response.json()["amount_raised"] == 1.0 + assert response.json()["amount_raised"] == 100 # # tickets @@ -387,7 +387,7 @@ def test_create_packtickets(client: TestClient) -> None: "/tombola/pack_tickets", json={ "raffle_id": raffle.id, - "price": 1.23, + "price": 123, "pack_size": 5, }, headers={"Authorization": f"Bearer {token}"}, @@ -402,7 +402,7 @@ def test_edit_packtickets(client: TestClient) -> None: f"/tombola/pack_tickets/{packticket.id}", json={ "raffle_id": raffle.id, - "price": 10.0, + "price": 1000, "pack_size": 5, }, headers={"Authorization": f"Bearer {token}"}, From f19e1c08ad9612daa9592f0940c17db363ecc2b6 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 1 Apr 2025 12:59:45 +0200 Subject: [PATCH 05/15] Fix: uncomment Redis lines --- app/modules/amap/endpoints_amap.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index 8759e0a440..a07413afcb 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -462,15 +462,15 @@ async def add_order_to_delievery( if not amount: raise HTTPException(status_code=400, detail="You can't order nothing") - """ + redis_key = "amap_" + order.user_id - if not isinstance(redis_client, Redis) or locker_get( - redis_client=redis_client, - key=redis_key, - ): - raise HTTPException(status_code=429, detail="Too fast !") - locker_set(redis_client=redis_client, key=redis_key, lock=True) - """ + if not isinstance(redis_client, Redis) or locker_get( + redis_client=redis_client, + key=redis_key, + ): + raise HTTPException(status_code=429, detail="Too fast !") + locker_set(redis_client=redis_client, key=redis_key, lock=True) + try: await cruds_amap.add_order_to_delivery( order=db_order, @@ -583,15 +583,13 @@ async def edit_order_from_delivery( if not balance: raise HTTPException(status_code=404, detail="No cash found") - """ redis_key = "amap_" + previous_order.user_id - if not isinstance(redis_client, Redis) or locker_get( - redis_client=redis_client, - key=redis_key, - ): - raise HTTPException(status_code=429, detail="Too fast !") - locker_set(redis_client=redis_client, key=redis_key, lock=True) - """ + if not isinstance(redis_client, Redis) or locker_get( + redis_client=redis_client, + key=redis_key, + ): + raise HTTPException(status_code=429, detail="Too fast !") + locker_set(redis_client=redis_client, key=redis_key, lock=True) try: await cruds_amap.edit_order_with_products( From bdf0ca7295871dab5ca933ac231c5d06bb3d07f0 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 1 Apr 2025 13:14:11 +0200 Subject: [PATCH 06/15] Fix: rebase --- .../versions/{29-price_in_cents.py => 32-price_in_cents.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename migrations/versions/{29-price_in_cents.py => 32-price_in_cents.py} (99%) diff --git a/migrations/versions/29-price_in_cents.py b/migrations/versions/32-price_in_cents.py similarity index 99% rename from migrations/versions/29-price_in_cents.py rename to migrations/versions/32-price_in_cents.py index c54034c479..5d3629ec9c 100644 --- a/migrations/versions/29-price_in_cents.py +++ b/migrations/versions/32-price_in_cents.py @@ -18,7 +18,7 @@ # revision identifiers, used by Alembic. revision: str = "4ae072a7e867" -down_revision: str | None = "c778706af06f" +down_revision: str | None = "e382ba1d64c2" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None From 06d38981a2d04a1924c9192987455c99083866a1 Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 1 Apr 2025 13:30:04 +0200 Subject: [PATCH 07/15] Fix: tests --- app/modules/raffle/endpoints_raffle.py | 2 +- tests/test_raffle.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/modules/raffle/endpoints_raffle.py b/app/modules/raffle/endpoints_raffle.py index 80c1965085..32796664bd 100644 --- a/app/modules/raffle/endpoints_raffle.py +++ b/app/modules/raffle/endpoints_raffle.py @@ -469,7 +469,7 @@ async def buy_ticket( user_id=user.id, ) balance = models_raffle.Cash( - **new_cash_db.dict(), + **new_cash_db.model_dump(), ) await cruds_raffle.create_cash_of_user( cash=balance, diff --git a/tests/test_raffle.py b/tests/test_raffle.py index 2865da9353..4e7e43ea16 100644 --- a/tests/test_raffle.py +++ b/tests/test_raffle.py @@ -137,7 +137,7 @@ async def init_objects() -> None: ) await add_object_to_db(prize_to_draw) - cash = models_raffle.Cash(user_id=student_user.id, balance=66) + cash = models_raffle.Cash(user_id=student_user.id, balance=6600) await add_object_to_db(cash) From 57a596b3b49924dfe61ace55940131f6fd45638b Mon Sep 17 00:00:00 2001 From: Marc-Andrieu <146140470+Marc-Andrieu@users.noreply.github.com> Date: Wed, 2 Apr 2025 15:36:27 +0200 Subject: [PATCH 08/15] Migration: test all edge cases with real data from prod --- migrations/versions/32-price_in_cents.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/migrations/versions/32-price_in_cents.py b/migrations/versions/32-price_in_cents.py index 5d3629ec9c..a08ab67d2a 100644 --- a/migrations/versions/32-price_in_cents.py +++ b/migrations/versions/32-price_in_cents.py @@ -150,7 +150,7 @@ def pre_test_upgrade( "amap_cash", { "user_id": user_id, - "balance": 11.56, + "balance": 3.3999999999999964, }, ) alembic_runner.insert_into( @@ -158,7 +158,7 @@ def pre_test_upgrade( { "id": uuid4(), "name": "name", - "price": 10.511111, + "price": 1.1000000000000014, "category": "category", }, ) @@ -166,7 +166,7 @@ def pre_test_upgrade( "raffle_cash", { "user_id": user_id, - "balance": 4.99999999997, + "balance": 1.4210854715202004e-14, }, ) alembic_runner.insert_into( @@ -182,7 +182,7 @@ def pre_test_upgrade( "raffle_pack_ticket", { "id": uuid4(), - "price": 7.5, + "price": -3.552713678800501e-15, "pack_size": 5, "raffle_id": raffle_id, }, @@ -196,21 +196,21 @@ def test_upgrade( amap_cash = alembic_connection.execute( sa.text(f"SELECT balance FROM amap_cash WHERE user_id = '{user_id}'"), ).fetchall() - assert amap_cash[0][0] == 1156 + assert amap_cash[0][0] == 340 amap_product = alembic_connection.execute( sa.text("SELECT price FROM amap_product WHERE name = 'name'"), ).fetchall() - assert amap_product[0][0] == 1051 + assert amap_product[0][0] == 110 raffle_cash = alembic_connection.execute( sa.text(f"SELECT balance FROM raffle_cash WHERE user_id = '{user_id}'"), ).fetchall() - assert raffle_cash[0][0] == 500 + assert raffle_cash[0][0] == 0 raffle_pack_ticket = alembic_connection.execute( sa.text( f"SELECT price FROM raffle_pack_ticket WHERE raffle_id = '{raffle_id}'", ), ).fetchall() - assert raffle_pack_ticket[0][0] == 750 + assert raffle_pack_ticket[0][0] == 0 From 041fa26cb38c69d030d83d1023ca5a5d7304746d Mon Sep 17 00:00:00 2001 From: Thonyk Date: Tue, 8 Apr 2025 02:50:46 +0200 Subject: [PATCH 09/15] Fix: uncomment necessary lines --- app/modules/amap/endpoints_amap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index a07413afcb..84f85f80f3 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -493,8 +493,8 @@ async def add_order_to_delievery( except ValueError as error: raise HTTPException(status_code=400, detail=str(error)) - # finally: - # locker_set(redis_client=redis_client, key=redis_key, lock=False) + finally: + locker_set(redis_client=redis_client, key=redis_key, lock=False) @module.router.patch( @@ -613,8 +613,8 @@ async def edit_order_from_delivery( except ValueError as error: raise HTTPException(status_code=400, detail=str(error)) - # finally: - # locker_set(redis_client=redis_client, key=redis_key, lock=False) + finally: + locker_set(redis_client=redis_client, key=redis_key, lock=False) @module.router.delete( From e00f9f9e83e3f53a3de6dc2772fa270aa4c154f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BChmos?= Date: Sat, 29 Nov 2025 23:08:25 +0100 Subject: [PATCH 10/15] corrected numbering and updated downrevision num --- .../versions/{43_promo_above_2000.py => 45_promo_above_2000.py} | 0 .../versions/{32-price_in_cents.py => 46-price_in_cents.py} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename migrations/versions/{43_promo_above_2000.py => 45_promo_above_2000.py} (100%) rename migrations/versions/{32-price_in_cents.py => 46-price_in_cents.py} (99%) diff --git a/migrations/versions/43_promo_above_2000.py b/migrations/versions/45_promo_above_2000.py similarity index 100% rename from migrations/versions/43_promo_above_2000.py rename to migrations/versions/45_promo_above_2000.py diff --git a/migrations/versions/32-price_in_cents.py b/migrations/versions/46-price_in_cents.py similarity index 99% rename from migrations/versions/32-price_in_cents.py rename to migrations/versions/46-price_in_cents.py index a08ab67d2a..01bc7da1f7 100644 --- a/migrations/versions/32-price_in_cents.py +++ b/migrations/versions/46-price_in_cents.py @@ -18,7 +18,7 @@ # revision identifiers, used by Alembic. revision: str = "4ae072a7e867" -down_revision: str | None = "e382ba1d64c2" +down_revision: str | None = "91fadc90f892" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None From dd58253e9d0c329008800d7976db96472e66a391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BChmos?= Date: Sat, 29 Nov 2025 23:30:02 +0100 Subject: [PATCH 11/15] format --- app/modules/amap/endpoints_amap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index 439922c52b..41b046f059 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -888,7 +888,7 @@ async def create_cash_of_user( message = Message( title="AMAP - Solde mis à jour", - content=f"Votre nouveau solde est de {cash.balance//100}€{cash.balance%100}.", + content=f"Votre nouveau solde est de {cash.balance // 100}€{cash.balance % 100}.", action_module="amap", ) await notification_tool.send_notification_to_user( From 070deee945c62749811df5191f87d84672d43183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BChmos?= Date: Sat, 29 Nov 2025 23:46:18 +0100 Subject: [PATCH 12/15] fix factories --- app/modules/amap/factory_amap.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/modules/amap/factory_amap.py b/app/modules/amap/factory_amap.py index bde9f78eef..c4214427b3 100644 --- a/app/modules/amap/factory_amap.py +++ b/app/modules/amap/factory_amap.py @@ -16,14 +16,14 @@ class AmapFactory(Factory): @classmethod async def create_products(cls, db: AsyncSession): # Generates sample products - products: dict[str, tuple[float, str]] = { - "banane": (5.0, "Fruits"), - "pomme": (6.0, "Fruits"), - "poire": (4.0, "Fruits"), - "kiwi": (3.0, "Fruits"), - "orange": (2.0, "Fruits"), - "carotte": (1.0, "Légumes"), - "tomate": (2.0, "Légumes"), + products: dict[str, tuple[int, str]] = { + "banane": (500, "Fruits"), + "pomme": (600, "Fruits"), + "poire": (400, "Fruits"), + "kiwi": (300, "Fruits"), + "orange": (200, "Fruits"), + "carotte": (100, "Légumes"), + "tomate": (200, "Légumes"), } for product_name, product_data in products.items(): @@ -67,7 +67,7 @@ async def create_cash_of_user(cls, db: AsyncSession): db=db, cash=models_amap.Cash( user_id=CoreUsersFactory.demo_users_id[0], - balance=100, + balance=10000, ), ) From a837c663d086b074d1453a9c0f85459f116738c3 Mon Sep 17 00:00:00 2001 From: Maillard Antoine <145469528+cotanoine@users.noreply.github.com> Date: Sun, 30 Nov 2025 01:51:46 +0100 Subject: [PATCH 13/15] added names to amap deliveries (#835) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds names to deliveries from the Amap module --------- Co-authored-by: Lühmos --- app/modules/amap/cruds_amap.py | 31 ++++---- app/modules/amap/endpoints_amap.py | 72 ++++++++++++++----- app/modules/amap/factory_amap.py | 3 + app/modules/amap/models_amap.py | 15 +++- app/modules/amap/schemas_amap.py | 10 +-- migrations/versions/47-amap_delivery_names.py | 72 +++++++++++++++++++ tests/modules/test_amap.py | 21 ++++-- 7 files changed, 180 insertions(+), 44 deletions(-) create mode 100644 migrations/versions/47-amap_delivery_names.py diff --git a/app/modules/amap/cruds_amap.py b/app/modules/amap/cruds_amap.py index f0a13b1732..014a6e30d2 100644 --- a/app/modules/amap/cruds_amap.py +++ b/app/modules/amap/cruds_amap.py @@ -2,7 +2,7 @@ import logging from collections.abc import Sequence -from datetime import date +from datetime import datetime from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession @@ -118,16 +118,6 @@ async def get_delivery_by_id( return result.scalars().first() -async def is_there_a_delivery_on(db: AsyncSession, delivery_date: date) -> bool: - result = await db.execute( - select(models_amap.Delivery).where( - models_amap.Delivery.delivery_date == delivery_date, - models_amap.Delivery.status != DeliveryStatusType.archived, - ), - ) - return result.scalars().all() != [] - - async def create_delivery( delivery: schemas_amap.DeliveryComplete, db: AsyncSession, @@ -248,6 +238,7 @@ async def get_products_of_order( async def add_order_to_delivery( db: AsyncSession, order: schemas_amap.OrderComplete, + delivery: models_amap.Delivery, ): db.add( models_amap.Order( @@ -358,7 +349,7 @@ async def add_cash(db: AsyncSession, user_id: str, amount: float): await db.execute( update(models_amap.Cash) .where(models_amap.Cash.user_id == user_id) - .values(user_id=balance.user_id, balance=balance.balance + amount), + .values(balance=balance.balance + amount), ) await db.flush() @@ -372,7 +363,21 @@ async def remove_cash(db: AsyncSession, user_id: str, amount: float): await db.execute( update(models_amap.Cash) .where(models_amap.Cash.user_id == user_id) - .values(user_id=balance.user_id, balance=balance.balance - amount), + .values(balance=balance.balance - amount), + ) + await db.flush() + + +async def update_last_ordering_date(db: AsyncSession, user_id: str, date: datetime): + result = await db.execute( + select(models_amap.Cash).where(models_amap.Cash.user_id == user_id), + ) + balance = result.scalars().first() + if balance is not None: + await db.execute( + update(models_amap.Cash) + .where(models_amap.Cash.user_id == user_id) + .values(last_order_date=date), ) await db.flush() diff --git a/app/modules/amap/endpoints_amap.py b/app/modules/amap/endpoints_amap.py index 41b046f059..250a69e49b 100644 --- a/app/modules/amap/endpoints_amap.py +++ b/app/modules/amap/endpoints_amap.py @@ -196,14 +196,6 @@ async def create_delivery( status=DeliveryStatusType.creation, **delivery.model_dump(), ) - if await cruds_amap.is_there_a_delivery_on( - db=db, - delivery_date=db_delivery.delivery_date, - ): - raise HTTPException( - status_code=400, - detail="There is already a delivery planned that day.", - ) return await cruds_amap.create_delivery(delivery=db_delivery, db=db) @@ -359,7 +351,14 @@ async def get_orders_from_delivery( schemas_amap.ProductQuantity(**product.__dict__) for product in order_content ] - res.append(schemas_amap.OrderReturn(productsdetail=products, **order.__dict__)) + res.append( + schemas_amap.OrderReturn( + productsdetail=products, + delivery_date=delivery.delivery_date, + delivery_name=delivery.name, + **order.__dict__, + ), + ) return res @@ -384,7 +383,12 @@ async def get_order_by_id( raise HTTPException(status_code=404, detail="Delivery not found") products = await cruds_amap.get_products_of_order(db=db, order_id=order_id) - return schemas_amap.OrderReturn(productsdetail=products, **order.__dict__) + return schemas_amap.OrderReturn( + productsdetail=products, + delivery_name=order.delivery.name, + delivery_date=order.delivery.delivery_date, + **order.__dict__, + ) @module.router.post( @@ -443,7 +447,6 @@ async def add_order_to_delievery( order_id=order_id, amount=amount, ordering_date=ordering_date, - delivery_date=delivery.delivery_date, **order.model_dump(), ) balance: models_amap.Cash | None = await cruds_amap.get_cash_by_id( @@ -453,12 +456,10 @@ async def add_order_to_delievery( # If the balance does not exist, we create a new one with a balance of 0 if not balance: - new_cash_db = schemas_amap.CashDB( + balance = models_amap.Cash( balance=0, user_id=order.user_id, - ) - balance = models_amap.Cash( - **new_cash_db.model_dump(), + last_order_date=ordering_date, ) await cruds_amap.create_cash_of_user( cash=balance, @@ -480,6 +481,7 @@ async def add_order_to_delievery( await cruds_amap.add_order_to_delivery( order=db_order, db=db, + delivery=delivery, ) await cruds_amap.remove_cash( db=db, @@ -487,14 +489,28 @@ async def add_order_to_delievery( amount=amount, ) + await cruds_amap.update_last_ordering_date( + db=db, + user_id=order.user_id, + date=ordering_date, + ) + orderret = await cruds_amap.get_order_by_id(order_id=db_order.order_id, db=db) productsret = await cruds_amap.get_products_of_order(db=db, order_id=order_id) hyperion_amap_logger.info( f"Add_order_to_delivery: An order has been created for user {order.user_id} for an amount of {amount}€. ({request_id})", ) - return schemas_amap.OrderReturn(productsdetail=productsret, **orderret.__dict__) + if orderret is None: + raise HTTPException(status_code=404, detail="added order not found") + + return schemas_amap.OrderReturn( + productsdetail=productsret, + delivery_name=orderret.delivery.name, + delivery_date=orderret.delivery.delivery_date, + **orderret.__dict__, + ) finally: locker_set(redis_client=redis_client, key=redis_key, lock=False) @@ -605,6 +621,12 @@ async def edit_order_from_delivery( user_id=previous_order.user_id, amount=previous_amount, ) + date = datetime.now(UTC) + await cruds_amap.update_last_ordering_date( + db=db, + user_id=previous_order.user_id, + date=date, + ) hyperion_amap_logger.info( f"Edit_order: Order {order_id} has been edited for user {db_order.user_id}. Amount was {previous_amount}€, is now {amount}€. ({request_id})", ) @@ -833,6 +855,7 @@ async def get_cash_by_id( balance=0, user_id=user_id, user=schemas_users.CoreUserSimple(**user_db.__dict__), + last_order_date=datetime.now(UTC), ) return cash @@ -868,7 +891,11 @@ async def create_cash_of_user( detail="This user already has a cash.", ) - cash_db = models_amap.Cash(user_id=user_id, balance=cash.balance) + cash_db = models_amap.Cash( + user_id=user_id, + balance=cash.balance, + last_order_date=datetime.now(UTC), + ) await cruds_amap.create_cash_of_user( cash=cash_db, @@ -965,7 +992,16 @@ async def get_orders_of_user( db=db, order_id=order.order_id, ) - res.append(schemas_amap.OrderReturn(productsdetail=products, **order.__dict__)) + if order is None: + raise HTTPException(status_code=404, detail="at least one order not found") + res.append( + schemas_amap.OrderReturn( + productsdetail=products, + delivery_date=order.delivery.delivery_date, + delivery_name=order.delivery.name, + **order.__dict__, + ), + ) return res diff --git a/app/modules/amap/factory_amap.py b/app/modules/amap/factory_amap.py index c4214427b3..e771acacf1 100644 --- a/app/modules/amap/factory_amap.py +++ b/app/modules/amap/factory_amap.py @@ -45,6 +45,7 @@ async def create_delivery(cls, db: AsyncSession): db=db, delivery=schemas_amap.DeliveryComplete( id=str(uuid.uuid4()), + name="Première livraison", status=DeliveryStatusType.orderable, delivery_date=(datetime.now(UTC) + timedelta(days=8)).date(), products_ids=[product.id for product in products], @@ -55,6 +56,7 @@ async def create_delivery(cls, db: AsyncSession): db=db, delivery=schemas_amap.DeliveryComplete( id=str(uuid.uuid4()), + name="Deuxième livraison", status=DeliveryStatusType.orderable, delivery_date=(datetime.now(UTC) + timedelta(days=1)).date(), products_ids=[product.id for product in products], @@ -68,6 +70,7 @@ async def create_cash_of_user(cls, db: AsyncSession): cash=models_amap.Cash( user_id=CoreUsersFactory.demo_users_id[0], balance=10000, + last_order_date=datetime.now(UTC), ), ) diff --git a/app/modules/amap/models_amap.py b/app/modules/amap/models_amap.py index 9ec2434c0c..0524e3a2d0 100644 --- a/app/modules/amap/models_amap.py +++ b/app/modules/amap/models_amap.py @@ -52,12 +52,17 @@ class Delivery(Base): __tablename__ = "amap_delivery" id: Mapped[str] = mapped_column(primary_key=True, index=True) + name: Mapped[str] = mapped_column(unique=False) delivery_date: Mapped[date] = mapped_column( unique=False, index=True, ) status: Mapped[DeliveryStatusType] = mapped_column(String) - orders: Mapped[list["Order"]] = relationship("Order", init=False) + orders: Mapped[list["Order"]] = relationship( + "Order", + init=False, + back_populates="delivery", + ) products: Mapped[list[Product]] = relationship( "Product", secondary="amap_delivery_content", @@ -79,7 +84,12 @@ class Order(Base): amount: Mapped[int] collection_slot: Mapped[AmapSlotType] ordering_date: Mapped[datetime] - delivery_date: Mapped[date] + delivery: Mapped["Delivery"] = relationship( + "Delivery", + lazy="joined", + init=False, + back_populates="orders", + ) user: Mapped[CoreUser] = relationship( "CoreUser", init=False, @@ -100,6 +110,7 @@ class Cash(Base): primary_key=True, ) balance: Mapped[int] + last_order_date: Mapped[datetime] user: Mapped[CoreUser] = relationship("CoreUser", init=False) diff --git a/app/modules/amap/schemas_amap.py b/app/modules/amap/schemas_amap.py index 9647ec13f8..bc77de2265 100644 --- a/app/modules/amap/schemas_amap.py +++ b/app/modules/amap/schemas_amap.py @@ -47,6 +47,7 @@ class ProductQuantity(BaseModel): class DeliveryBase(BaseModel): """Base schema for AMAP deliveries""" + name: str delivery_date: date products_ids: list[str] = [] @@ -58,6 +59,7 @@ class DeliveryComplete(DeliveryBase): class DeliveryUpdate(BaseModel): + name: str | None = None delivery_date: date | None = None @@ -77,13 +79,13 @@ class OrderComplete(OrderBase): order_id: str amount: int ordering_date: datetime - delivery_date: date model_config = ConfigDict(from_attributes=True) class OrderReturn(BaseModel): user: CoreUserSimple delivery_id: str + delivery_name: str productsdetail: Sequence[ProductQuantity] collection_slot: AmapSlotType order_id: str @@ -101,6 +103,7 @@ class OrderEdit(BaseModel): class DeliveryReturn(BaseModel): + name: str delivery_date: date products: list[ProductComplete] = [] id: str @@ -121,10 +124,7 @@ class CashBase(BaseModel): class CashComplete(CashBase): user: CoreUserSimple - - -class CashDB(CashBase): - user_id: str + last_order_date: datetime class CashEdit(BaseModel): diff --git a/migrations/versions/47-amap_delivery_names.py b/migrations/versions/47-amap_delivery_names.py new file mode 100644 index 0000000000..89b56665d6 --- /dev/null +++ b/migrations/versions/47-amap_delivery_names.py @@ -0,0 +1,72 @@ +"""empty message + +Create Date: 2025-10-21 19:53:38.521697 +""" + +from collections.abc import Sequence +from datetime import UTC, datetime +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pytest_alembic import MigrationContext + +import sqlalchemy as sa +from alembic import op + +from app.types.sqlalchemy import TZDateTime + +# revision identifiers, used by Alembic. +revision: str = "9fc3dc926600" +down_revision: str | None = "4ae072a7e867" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + op.add_column("amap_delivery", sa.Column("name", sa.String(), nullable=True)) + op.execute("UPDATE amap_delivery SET name = ''") + op.alter_column("amap_delivery", "name", nullable=False) + + op.add_column( + "amap_cash", + sa.Column("last_order_date", TZDateTime(), nullable=True), + ) + default_time = datetime(2025, 1, 1, tzinfo=UTC) + op.execute( + sa.text("UPDATE amap_cash SET last_order_date = :last_order_date").bindparams( + sa.bindparam("last_order_date", value=default_time), + ), + ) + op.alter_column("amap_cash", "last_order_date", nullable=False) + + op.drop_column("amap_order", "delivery_date") + + +def downgrade() -> None: + op.drop_column("amap_cash", "last_order_date") + op.drop_column("amap_delivery", "name") + op.add_column( + "amap_order", + sa.Column("delivery_date", TZDateTime(), nullable=True), + ) + default_time = datetime(2025, 1, 1, tzinfo=UTC) + op.execute( + sa.text("UPDATE amap_order SET delivery_date = :delivery_date").bindparams( + sa.bindparam("delivery_date", value=default_time), + ), + ) + op.alter_column("amap_order", "delivery_date", nullable=False) + + +def pre_test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass + + +def test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass diff --git a/tests/modules/test_amap.py b/tests/modules/test_amap.py index cea0324eee..6c20b12031 100644 --- a/tests/modules/test_amap.py +++ b/tests/modules/test_amap.py @@ -58,17 +58,18 @@ async def init_objects() -> None: ) await add_object_to_db(deletable_product) - # We can not create two deliveries with the same date delivery = models_amap.Delivery( id=str(uuid.uuid4()), delivery_date=datetime(2022, 8, 15, tzinfo=UTC), status=DeliveryStatusType.creation, + name="Livraison 1", ) await add_object_to_db(delivery) deletable_delivery = models_amap.Delivery( id=str(uuid.uuid4()), delivery_date=datetime(2022, 8, 16, tzinfo=UTC), status=DeliveryStatusType.creation, + name="Livraison supprimable", ) await add_object_to_db(deletable_delivery) @@ -76,6 +77,7 @@ async def init_objects() -> None: id=str(uuid.uuid4()), delivery_date=datetime(2022, 8, 17, tzinfo=UTC), status=DeliveryStatusType.locked, + name="Livraison verrouillée", ) await add_object_to_db(locked_delivery) @@ -86,7 +88,6 @@ async def init_objects() -> None: amount=0, collection_slot=AmapSlotType.midi, ordering_date=datetime(2022, 8, 10, 12, 16, 26, tzinfo=UTC), - delivery_date=delivery.delivery_date, ) await add_object_to_db(order) @@ -97,11 +98,14 @@ async def init_objects() -> None: amount=0, collection_slot=AmapSlotType.midi, ordering_date=datetime(2022, 8, 18, 12, 16, 26, tzinfo=UTC), - delivery_date=locked_delivery.delivery_date, ) await add_object_to_db(deletable_order_by_admin) - cash = models_amap.Cash(user_id=student_user.id, balance=666) + cash = models_amap.Cash( + user_id=student_user.id, + balance=666, + last_order_date=datetime.now(UTC), + ) await add_object_to_db(cash) @@ -159,7 +163,7 @@ def test_delete_product(client: TestClient) -> None: def test_get_deliveries(client: TestClient) -> None: - # The user don't need to be part of group amap to get a product + # The user don't need to be part of group amap to get a delivery student_token = create_api_access_token(student_user) response = client.get( @@ -175,6 +179,7 @@ def test_create_delivery(client: TestClient) -> None: response = client.post( "/amap/deliveries", json={ + "name": "Livraison", "delivery_date": "2022-08-18", "products_ids": [product.id], "locked": False, @@ -199,7 +204,11 @@ def test_edit_delivery(client: TestClient) -> None: response = client.patch( f"/amap/deliveries/{delivery.id}", - json={"delivery_date": "2022-08-18", "locked": False}, + json={ + "name": "Livraison editee", + "delivery_date": "2022-08-18", + "locked": False, + }, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 204 From 7fe109276a5dac58fa5aeb1a54b00a562703e09d Mon Sep 17 00:00:00 2001 From: Marc Andrieu <146140470+Marc-Andrieu@users.noreply.github.com> Date: Wed, 7 Jan 2026 01:10:25 +0100 Subject: [PATCH 14/15] let the merge do that --- migrations/versions/45_promo_above_2000.py | 101 --------------------- 1 file changed, 101 deletions(-) delete mode 100644 migrations/versions/45_promo_above_2000.py diff --git a/migrations/versions/45_promo_above_2000.py b/migrations/versions/45_promo_above_2000.py deleted file mode 100644 index 0c53e34eb5..0000000000 --- a/migrations/versions/45_promo_above_2000.py +++ /dev/null @@ -1,101 +0,0 @@ -"""43-promo-above-2000 - -Create Date: 2025-09-07 09:54:34.421809 -""" - -import uuid -from collections.abc import Sequence -from typing import TYPE_CHECKING - -from app.core.schools.schools_type import SchoolType - -if TYPE_CHECKING: - from pytest_alembic import MigrationContext - -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "91fadc90f892" -down_revision: str | None = "52ce74575f" -branch_labels: str | Sequence[str] | None = None -depends_on: str | Sequence[str] | None = None - - -def upgrade() -> None: - op.execute("UPDATE core_user SET promo = 2000 + promo WHERE promo < 2000") - - -def downgrade() -> None: - # we afterwards cannot distinguish those who had 2023 from 23 - pass - - -user_id_23 = str(uuid.uuid4()) -user_id_2023 = str(uuid.uuid4()) -user_id_null = str(uuid.uuid4()) - - -def pre_test_upgrade( - alembic_runner: "MigrationContext", - alembic_connection: sa.Connection, -) -> None: - alembic_runner.insert_into( - "core_user", - [ - { - "id": user_id_23, - "email": "email23", - "school_id": str(SchoolType.no_school.value), - "password_hash": "password_hash", - "account_type": "student", - "name": "name", - "firstname": "firstname", - "promo": 23, - }, - { - "id": user_id_2023, - "email": "email2023", - "school_id": str(SchoolType.no_school.value), - "password_hash": "password_hash", - "account_type": "student", - "name": "name", - "firstname": "firstname", - "promo": 2023, - }, - { - "id": user_id_null, - "email": "emailnull", - "school_id": str(SchoolType.no_school.value), - "password_hash": "password_hash", - "account_type": "student", - "name": "name", - "firstname": "firstname", - # promo is null - }, - ], - ) - - -def test_upgrade( - alembic_runner: "MigrationContext", - alembic_connection: sa.Connection, -) -> None: - assert ( - alembic_connection.execute( - sa.text(f"SELECT promo FROM core_user WHERE id = '{user_id_23}'"), - ).all()[0][0] - == 2023 - ) - assert ( - alembic_connection.execute( - sa.text(f"SELECT promo FROM core_user WHERE id = '{user_id_2023}'"), - ).all()[0][0] - == 2023 - ) - assert ( - alembic_connection.execute( - sa.text(f"SELECT promo FROM core_user WHERE id = '{user_id_null}'"), - ).all()[0][0] - is None - ) From 53043d6f28d8287e1435c7571d37cf1090c91485 Mon Sep 17 00:00:00 2001 From: Marc-Andrieu Date: Wed, 7 Jan 2026 01:17:05 +0100 Subject: [PATCH 15/15] Fix migration order --- .../versions/{46-price_in_cents.py => 52-price_in_cents.py} | 2 +- .../{47-amap_delivery_names.py => 53-amap_delivery_names.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename migrations/versions/{46-price_in_cents.py => 52-price_in_cents.py} (99%) rename migrations/versions/{47-amap_delivery_names.py => 53-amap_delivery_names.py} (100%) diff --git a/migrations/versions/46-price_in_cents.py b/migrations/versions/52-price_in_cents.py similarity index 99% rename from migrations/versions/46-price_in_cents.py rename to migrations/versions/52-price_in_cents.py index 01bc7da1f7..f563ccd3f9 100644 --- a/migrations/versions/46-price_in_cents.py +++ b/migrations/versions/52-price_in_cents.py @@ -18,7 +18,7 @@ # revision identifiers, used by Alembic. revision: str = "4ae072a7e867" -down_revision: str | None = "91fadc90f892" +down_revision: str | None = "b04f76f4198f" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None diff --git a/migrations/versions/47-amap_delivery_names.py b/migrations/versions/53-amap_delivery_names.py similarity index 100% rename from migrations/versions/47-amap_delivery_names.py rename to migrations/versions/53-amap_delivery_names.py