Skip to content

Commit 0e03c0e

Browse files
authored
CDR : Add needs_validation in CDRProduct (#791)
### Description Please explain the changes you made here. ### Checklist - [ ] Created tests which fail without the change (if possible) - [ ] All tests passing - [ ] Extended the documentation, if necessary
1 parent 868767d commit 0e03c0e

File tree

7 files changed

+101
-3
lines changed

7 files changed

+101
-3
lines changed

app/modules/cdr/cruds_cdr.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,15 @@ async def update_product(
178178
.values(
179179
**product.model_dump(
180180
exclude_none=True,
181-
exclude={"product_constraints", "document_constraints"},
181+
exclude={
182+
"product_constraints",
183+
"document_constraints",
184+
"related_membership",
185+
},
182186
),
187+
related_membership_id=product.related_membership.id
188+
if product.related_membership
189+
else None,
183190
),
184191
)
185192

@@ -895,7 +902,19 @@ async def delete_customdata(db: AsyncSession, field_id: UUID, user_id: str):
895902

896903
async def get_pending_validation_users(db: AsyncSession) -> Sequence[CoreUser]:
897904
result = await db.execute(
898-
select(models_cdr.Purchase).where(models_cdr.Purchase.validated.is_(False)),
905+
select(models_cdr.Purchase)
906+
.join(
907+
models_cdr.ProductVariant,
908+
models_cdr.Purchase.product_variant_id == models_cdr.ProductVariant.id,
909+
)
910+
.join(
911+
models_cdr.CdrProduct,
912+
models_cdr.ProductVariant.product_id == models_cdr.CdrProduct.id,
913+
)
914+
.where(
915+
models_cdr.Purchase.validated.is_(False),
916+
models_cdr.CdrProduct.needs_validation.is_(True),
917+
),
899918
)
900919
user_ids = set(purchase.user_id for purchase in result.scalars().all())
901920
result_users = await db.execute(select(CoreUser).where(CoreUser.id.in_(user_ids)))

app/modules/cdr/endpoints_cdr.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ async def create_product(
728728
name_fr=product.name_fr,
729729
name_en=product.name_en,
730730
available_online=product.available_online,
731+
needs_validation=product.needs_validation,
731732
description_fr=product.description_fr,
732733
description_en=product.description_en,
733734
related_membership_id=product.related_membership.id
@@ -923,6 +924,11 @@ async def create_product_variant(
923924
status_code=403,
924925
detail="CDR is closed. You cant add a new product.",
925926
)
927+
if product and not product.needs_validation and product_variant.price != 0:
928+
raise HTTPException(
929+
status_code=403,
930+
detail="A product that does not need validation must be free.",
931+
)
926932
db_product_variant = models_cdr.ProductVariant(
927933
id=uuid4(),
928934
product_id=product_id,
@@ -1032,6 +1038,15 @@ async def update_product_variant(
10321038
status_code=403,
10331039
detail="This product has no related membership. You can't specify a membership duration.",
10341040
)
1041+
if (
1042+
product_variant.price is not None
1043+
and db_product
1044+
and (not db_product.needs_validation and product_variant.price != 0)
1045+
):
1046+
raise HTTPException(
1047+
status_code=403,
1048+
detail="A product that does not need validation must be free.",
1049+
)
10351050

10361051
await cruds_cdr.update_product_variant(
10371052
variant_id=variant_id,
@@ -1266,6 +1281,7 @@ async def get_purchases_by_user_id(
12661281
name_fr=product.name_fr,
12671282
name_en=product.name_en,
12681283
available_online=product.available_online,
1284+
needs_validation=product.needs_validation,
12691285
description_fr=product.description_fr,
12701286
description_en=product.description_en,
12711287
related_membership=schemas_memberships.MembershipSimple(
@@ -1354,6 +1370,7 @@ async def get_purchases_by_user_id_by_seller_id(
13541370
name_fr=product.name_fr,
13551371
name_en=product.name_en,
13561372
available_online=product.available_online,
1373+
needs_validation=product.needs_validation,
13571374
description_fr=product.description_fr,
13581375
description_en=product.description_en,
13591376
related_membership=schemas_memberships.MembershipSimple(
@@ -1562,7 +1579,7 @@ async def mark_purchase_as_validated(
15621579
db=db,
15631580
product_id=product_variant.product_id,
15641581
)
1565-
if not product:
1582+
if not product or not product.needs_validation:
15661583
raise HTTPException(
15671584
status_code=404,
15681585
detail="Invalid product.",

app/modules/cdr/models_cdr.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class CdrProduct(Base):
7676
name_en: Mapped[str | None]
7777
available_online: Mapped[bool]
7878

79+
needs_validation: Mapped[bool]
80+
7981
description_fr: Mapped[str | None] = mapped_column(default=None)
8082
description_en: Mapped[str | None] = mapped_column(default=None)
8183
related_membership_id: Mapped[uuid.UUID | None] = mapped_column(

app/modules/cdr/schemas_cdr.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class ProductBase(BaseModel):
131131
description_fr: str | None = None
132132
description_en: str | None = None
133133
available_online: bool
134+
needs_validation: bool = True
134135
related_membership: schemas_memberships.MembershipSimple | None = None
135136
tickets: list[GenerateTicketBase] = []
136137
product_constraints: list[UUID]
@@ -143,6 +144,7 @@ class ProductCompleteNoConstraint(BaseModel):
143144
description_fr: str | None = None
144145
description_en: str | None = None
145146
available_online: bool
147+
needs_validation: bool
146148
id: UUID
147149
seller_id: UUID
148150
variants: list[ProductVariantComplete] = []
@@ -158,6 +160,7 @@ class ProductComplete(BaseModel):
158160
description_fr: str | None = None
159161
description_en: str | None = None
160162
available_online: bool
163+
needs_validation: bool
161164
id: UUID
162165
seller_id: UUID
163166
variants: list[ProductVariantComplete] = []
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""add product needs_validation
2+
3+
Create Date: 2025-08-18 16:04:30.438478
4+
"""
5+
6+
from collections.abc import Sequence
7+
from typing import TYPE_CHECKING
8+
9+
if TYPE_CHECKING:
10+
from pytest_alembic import MigrationContext
11+
12+
import sqlalchemy as sa
13+
from alembic import op
14+
15+
# revision identifiers, used by Alembic.
16+
revision: str = "98e2557c00c8"
17+
down_revision: str | None = "7da0e98a9e32"
18+
branch_labels: str | Sequence[str] | None = None
19+
depends_on: str | Sequence[str] | None = None
20+
21+
22+
def upgrade() -> None:
23+
op.add_column(
24+
"cdr_product",
25+
sa.Column("needs_validation", sa.Boolean(), nullable=True),
26+
)
27+
op.execute("UPDATE cdr_product SET needs_validation = true")
28+
op.alter_column("cdr_product", "needs_validation", nullable=False)
29+
30+
31+
def downgrade() -> None:
32+
op.drop_column("cdr_product", "needs_validation")
33+
34+
35+
def pre_test_upgrade(
36+
alembic_runner: "MigrationContext",
37+
alembic_connection: sa.Connection,
38+
) -> None:
39+
pass
40+
41+
42+
def test_upgrade(
43+
alembic_runner: "MigrationContext",
44+
alembic_connection: sa.Connection,
45+
) -> None:
46+
pass

tests/test_cdr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ async def init_objects():
132132
description_fr="Un Produit",
133133
description_en="A Product",
134134
available_online=False,
135+
needs_validation=True,
135136
)
136137
await add_object_to_db(product)
137138

@@ -144,6 +145,7 @@ async def init_objects():
144145
description_fr="Un Produit disponible en ligne",
145146
description_en="An online available Product",
146147
available_online=True,
148+
needs_validation=True,
147149
)
148150
await add_object_to_db(online_product)
149151

@@ -154,6 +156,7 @@ async def init_objects():
154156
name_fr="Produit sans variante",
155157
name_en="Unused product",
156158
available_online=False,
159+
needs_validation=True,
157160
)
158161
await add_object_to_db(empty_product)
159162

@@ -164,6 +167,7 @@ async def init_objects():
164167
name_fr="Produit utilisable",
165168
name_en="Usable product",
166169
available_online=False,
170+
needs_validation=True,
167171
)
168172
await add_object_to_db(usable_product)
169173

@@ -331,6 +335,7 @@ async def init_objects():
331335
name_fr="Produit a ticket",
332336
name_en="Usable product",
333337
available_online=False,
338+
needs_validation=True,
334339
)
335340
await add_object_to_db(ticket_product)
336341

@@ -2444,6 +2449,7 @@ async def test_validate_purchase(client: TestClient):
24442449
name_en="Product",
24452450
available_online=False,
24462451
related_membership_id=association_membership.id,
2452+
needs_validation=True,
24472453
)
24482454
await add_object_to_db(product_membership)
24492455
product_membership_to_purchase = models_cdr.CdrProduct(
@@ -2453,6 +2459,7 @@ async def test_validate_purchase(client: TestClient):
24532459
name_en="Product",
24542460
available_online=False,
24552461
related_membership_id=association_membership.id,
2462+
needs_validation=True,
24562463
)
24572464
await add_object_to_db(product_membership_to_purchase)
24582465
product_2 = models_cdr.CdrProduct(
@@ -2461,6 +2468,7 @@ async def test_validate_purchase(client: TestClient):
24612468
name_fr="Produit à adhésion",
24622469
name_en="Product",
24632470
available_online=False,
2471+
needs_validation=True,
24642472
)
24652473
await add_object_to_db(product_2)
24662474
variant_to_validate = models_cdr.ProductVariant(

tests/test_cdr_result.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ async def init_objects():
106106
description_fr="Un Produit",
107107
description_en="A Product",
108108
available_online=False,
109+
needs_validation=True,
109110
)
110111

111112
global product2
@@ -117,6 +118,7 @@ async def init_objects():
117118
description_fr="Un Produit2",
118119
description_en="A Product2",
119120
available_online=False,
121+
needs_validation=True,
120122
)
121123

122124
global product3
@@ -128,6 +130,7 @@ async def init_objects():
128130
description_fr="Un Produit3",
129131
description_en="A Product3",
130132
available_online=False,
133+
needs_validation=True,
131134
)
132135

133136
global customdata_field1

0 commit comments

Comments
 (0)