From eae671b8cf0d726023e7d215fa81943b8555ac82 Mon Sep 17 00:00:00 2001 From: Felix Evers Date: Tue, 22 Apr 2025 14:58:37 +0200 Subject: [PATCH] feat: add customer product status --- .../067f32395ad5_initialize_models.py | 176 ++++++++++++ ...88dd6_link_customer_product_and_invoice.py | 30 -- ...e6773_link_customer_product_and_invoice.py | 41 --- .../8288ec79df35_initialize_models.py | 261 ------------------ .../versions/9ce0def73b09_more_titles.py | 37 --- app/models/customer_product.py | 12 +- app/models/static.py | 11 + app/routers/customer_product.py | 19 +- 8 files changed, 207 insertions(+), 380 deletions(-) create mode 100644 app/migrations/versions/067f32395ad5_initialize_models.py delete mode 100644 app/migrations/versions/43e025f88dd6_link_customer_product_and_invoice.py delete mode 100644 app/migrations/versions/7d78060e6773_link_customer_product_and_invoice.py delete mode 100644 app/migrations/versions/8288ec79df35_initialize_models.py delete mode 100644 app/migrations/versions/9ce0def73b09_more_titles.py diff --git a/app/migrations/versions/067f32395ad5_initialize_models.py b/app/migrations/versions/067f32395ad5_initialize_models.py new file mode 100644 index 0000000..1de8e4b --- /dev/null +++ b/app/migrations/versions/067f32395ad5_initialize_models.py @@ -0,0 +1,176 @@ +"""initialize models + +Revision ID: 067f32395ad5 +Revises: +Create Date: 2025-04-22 14:39:11.438511 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '067f32395ad5' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('contracts', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('key', sa.Enum('AGB_APP_ZUM_DOC_PATIENT', 'AGB_MEDIQUU_CONNECT', 'AGB_APP_ZUM_DOC', 'AGB_MEDIQUU_NETZMANAGER', 'AGB_MEDIQUU_CHAT', 'PRIVACY_CONCEPT', 'PRIVACY_CONCEPT_TASKS', 'AVV', 'AVV_TASKS', 'NDA', 'SUB', 'TOM', name='contractkeyenum'), nullable=False), + sa.Column('version', sa.String(), nullable=False), + sa.Column('url', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('customers', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('email', sa.String(), nullable=False), + sa.Column('website_url', sa.String(), nullable=True), + sa.Column('phone_number', sa.String(), nullable=True), + sa.Column('address', sa.String(), nullable=False), + sa.Column('house_number', sa.String(), nullable=False), + sa.Column('care_of', sa.String(), nullable=True), + sa.Column('postal_code', sa.String(), nullable=False), + sa.Column('city', sa.String(), nullable=False), + sa.Column('country', sa.String(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('uuid'), + sa.UniqueConstraint('email') + ) + op.create_table('products', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('image_url', sa.Text(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('messages', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('customer_uuid', sa.UUID(), nullable=False), + sa.Column('subject', sa.String(), nullable=False), + sa.Column('message', sa.Text(), nullable=False), + sa.Column('status', sa.Enum('UNREAD', 'READ', 'ARCHIVED', name='messagestatusenum'), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['customer_uuid'], ['customers.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('product_contracts', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('product_uuid', sa.UUID(), nullable=False), + sa.Column('contract_uuid', sa.UUID(), nullable=False), + sa.ForeignKeyConstraint(['contract_uuid'], ['contracts.uuid'], ), + sa.ForeignKeyConstraint(['product_uuid'], ['products.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('product_plans', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('product_uuid', sa.UUID(), nullable=False), + sa.Column('type', sa.Enum('ONCE', 'RECURRING', 'LIFETIME', 'TRIAL', name='plantypeenum'), nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('cost_euro', sa.Numeric(), nullable=False), + sa.Column('recurring_month', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['product_uuid'], ['products.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('users', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('customer_uuid', sa.UUID(), nullable=True), + sa.Column('name', sa.String(), nullable=False), + sa.Column('email', sa.String(), nullable=False), + sa.Column('role', sa.Enum('ADMIN', 'NORMAL', name='roleenum'), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['customer_uuid'], ['customers.uuid'], ), + sa.PrimaryKeyConstraint('uuid'), + sa.UniqueConstraint('email') + ) + op.create_table('vouchers', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('code', sa.String(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('product_plan_uuid', sa.UUID(), nullable=False), + sa.Column('discount_percentage', sa.Numeric(), nullable=True), + sa.Column('discount_fixed_amount', sa.Numeric(), nullable=True), + sa.Column('valid_from', sa.DateTime(), nullable=False), + sa.Column('valid_until', sa.DateTime(), nullable=False), + sa.Column('max_redemptions', sa.Integer(), nullable=False), + sa.Column('redeemed_count', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['product_plan_uuid'], ['product_plans.uuid'], ), + sa.PrimaryKeyConstraint('uuid'), + sa.UniqueConstraint('code') + ) + op.create_table('customer_products', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('customer_uuid', sa.UUID(), nullable=False), + sa.Column('product_uuid', sa.UUID(), nullable=False), + sa.Column('product_plan_uuid', sa.UUID(), nullable=False), + sa.Column('status', sa.Enum('TRIALING', 'ACTIVE', 'PENDING_ACTIVATION', 'PENDING_PAYMENT', 'CANCELLATION_SCHEDULED', 'CANCELED', 'EXPIRED', 'REFUNDED', name='customerproductstatusenum'), nullable=False), + sa.Column('seats', sa.Integer(), nullable=True), + sa.Column('start_date', sa.DateTime(), nullable=False), + sa.Column('end_date', sa.DateTime(), nullable=False), + sa.Column('next_payment_date', sa.DateTime(), nullable=True), + sa.Column('voucher_uuid', sa.UUID(), nullable=True), + sa.Column('cancellation_date', sa.DateTime(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['customer_uuid'], ['customers.uuid'], ), + sa.ForeignKeyConstraint(['product_plan_uuid'], ['product_plans.uuid'], ), + sa.ForeignKeyConstraint(['product_uuid'], ['products.uuid'], ), + sa.ForeignKeyConstraint(['voucher_uuid'], ['vouchers.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('customer_product_contracts', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('product_customer_uuid', sa.UUID(), nullable=False), + sa.Column('contract_uuid', sa.UUID(), nullable=False), + sa.Column('accepted_at', sa.DateTime(), nullable=False), + sa.ForeignKeyConstraint(['contract_uuid'], ['contracts.uuid'], ), + sa.ForeignKeyConstraint(['product_customer_uuid'], ['customer_products.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + op.create_table('invoices', + sa.Column('uuid', sa.UUID(), nullable=False), + sa.Column('customer_uuid', sa.UUID(), nullable=False), + sa.Column('customer_product_uuid', sa.UUID(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('status', sa.Enum('PENDING', 'PAID', 'OVERDUE', name='invoicestatusenum'), nullable=False), + sa.Column('date', sa.DateTime(), nullable=False), + sa.Column('total_amount', sa.Numeric(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['customer_product_uuid'], ['customer_products.uuid'], ), + sa.ForeignKeyConstraint(['customer_uuid'], ['customers.uuid'], ), + sa.PrimaryKeyConstraint('uuid') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('invoices') + op.drop_table('customer_product_contracts') + op.drop_table('customer_products') + op.drop_table('vouchers') + op.drop_table('users') + op.drop_table('product_plans') + op.drop_table('product_contracts') + op.drop_table('messages') + op.drop_table('products') + op.drop_table('customers') + op.drop_table('contracts') + # ### end Alembic commands ### diff --git a/app/migrations/versions/43e025f88dd6_link_customer_product_and_invoice.py b/app/migrations/versions/43e025f88dd6_link_customer_product_and_invoice.py deleted file mode 100644 index 0f4c92d..0000000 --- a/app/migrations/versions/43e025f88dd6_link_customer_product_and_invoice.py +++ /dev/null @@ -1,30 +0,0 @@ -"""link customer product and invoice# - -Revision ID: 43e025f88dd6 -Revises: 9ce0def73b09 -Create Date: 2025-04-16 10:53:02.229030 - -""" - -from typing import Sequence, Union - -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "43e025f88dd6" -down_revision: Union[str, None] = "9ce0def73b09" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column("products", sa.Column("image_url", sa.Text(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column("products", "image_url") - # ### end Alembic commands ### diff --git a/app/migrations/versions/7d78060e6773_link_customer_product_and_invoice.py b/app/migrations/versions/7d78060e6773_link_customer_product_and_invoice.py deleted file mode 100644 index 1b715fa..0000000 --- a/app/migrations/versions/7d78060e6773_link_customer_product_and_invoice.py +++ /dev/null @@ -1,41 +0,0 @@ -"""link customer product and invoice - -Revision ID: 7d78060e6773 -Revises: 43e025f88dd6 -Create Date: 2025-04-16 10:56:04.022132 - -""" - -from typing import Sequence, Union - -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "7d78060e6773" -down_revision: Union[str, None] = "43e025f88dd6" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column( - "invoices", - sa.Column("customer_product_uuid", sa.UUID(), nullable=False), - ) - op.create_foreign_key( - None, - "invoices", - "customer_products", - ["customer_product_uuid"], - ["uuid"], - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "invoices", type_="foreignkey") - op.drop_column("invoices", "customer_product_uuid") - # ### end Alembic commands ### diff --git a/app/migrations/versions/8288ec79df35_initialize_models.py b/app/migrations/versions/8288ec79df35_initialize_models.py deleted file mode 100644 index 4001fe2..0000000 --- a/app/migrations/versions/8288ec79df35_initialize_models.py +++ /dev/null @@ -1,261 +0,0 @@ -"""initialize models - -Revision ID: 8288ec79df35 -Revises: -Create Date: 2025-04-02 01:07:49.352389 - -""" - -from typing import Sequence, Union - -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "8288ec79df35" -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "contracts", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column( - "key", - sa.Enum( - "AGB_APP_ZUM_DOC_PATIENT", - "AGB_MEDIQUU_CONNECT", - "AGB_APP_ZUM_DOC", - "AGB_MEDIQUU_NETZMANAGER", - "AGB_MEDIQUU_CHAT", - "PRIVACY_CONCEPT", - "PRIVACY_CONCEPT_TASKS", - "AVV", - "AVV_TASKS", - "NDA", - "SUB", - "TOM", - name="contractkeyenum", - ), - nullable=False, - ), - sa.Column("version", sa.String(), nullable=False), - sa.Column("url", sa.String(), nullable=True), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "customers", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("name", sa.String(), nullable=False), - sa.Column("email", sa.String(), nullable=False), - sa.Column("website_url", sa.String(), nullable=True), - sa.Column("phone_number", sa.String(), nullable=True), - sa.Column("address", sa.String(), nullable=False), - sa.Column("house_number", sa.String(), nullable=False), - sa.Column("care_of", sa.String(), nullable=True), - sa.Column("postal_code", sa.String(), nullable=False), - sa.Column("city", sa.String(), nullable=False), - sa.Column("country", sa.String(), nullable=False), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint("uuid"), - sa.UniqueConstraint("email"), - ) - op.create_table( - "products", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("name", sa.String(), nullable=False), - sa.Column("description", sa.Text(), nullable=True), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "invoices", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("customer_uuid", sa.UUID(), nullable=False), - sa.Column( - "status", - sa.Enum("PENDING", "PAID", "OVERDUE", name="invoicestatusenum"), - nullable=False, - ), - sa.Column("date", sa.DateTime(), nullable=False), - sa.Column("total_amount", sa.Numeric(), nullable=False), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["customer_uuid"], - ["customers.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "messages", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("customer_uuid", sa.UUID(), nullable=False), - sa.Column("subject", sa.String(), nullable=False), - sa.Column("message", sa.Text(), nullable=False), - sa.Column( - "status", - sa.Enum("UNREAD", "READ", "ARCHIVED", name="messagestatusenum"), - nullable=False, - ), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["customer_uuid"], - ["customers.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "product_contracts", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("product_uuid", sa.UUID(), nullable=False), - sa.Column("contract_uuid", sa.UUID(), nullable=False), - sa.ForeignKeyConstraint( - ["contract_uuid"], - ["contracts.uuid"], - ), - sa.ForeignKeyConstraint( - ["product_uuid"], - ["products.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "product_plans", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("product_uuid", sa.UUID(), nullable=False), - sa.Column( - "type", - sa.Enum( - "ONCE", - "RECURRING", - "LIFETIME", - "TRIAL", - name="plantypeenum"), - nullable=False, - ), - sa.Column("cost_euro", sa.Numeric(), nullable=False), - sa.Column("recurring_month", sa.Integer(), nullable=True), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["product_uuid"], - ["products.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "users", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("customer_uuid", sa.UUID(), nullable=True), - sa.Column("name", sa.String(), nullable=False), - sa.Column("email", sa.String(), nullable=False), - sa.Column( - "role", - sa.Enum( - "ADMIN", - "NORMAL", - name="roleenum"), - nullable=False), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["customer_uuid"], - ["customers.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - sa.UniqueConstraint("email"), - ) - op.create_table( - "vouchers", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("code", sa.String(), nullable=False), - sa.Column("description", sa.Text(), nullable=True), - sa.Column("product_plan_uuid", sa.UUID(), nullable=False), - sa.Column("discount_percentage", sa.Numeric(), nullable=True), - sa.Column("discount_fixed_amount", sa.Numeric(), nullable=True), - sa.Column("valid_from", sa.DateTime(), nullable=False), - sa.Column("valid_until", sa.DateTime(), nullable=False), - sa.Column("max_redemptions", sa.Integer(), nullable=False), - sa.Column("redeemed_count", sa.Integer(), nullable=True), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["product_plan_uuid"], - ["product_plans.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - sa.UniqueConstraint("code"), - ) - op.create_table( - "customer_products", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("customer_uuid", sa.UUID(), nullable=False), - sa.Column("product_uuid", sa.UUID(), nullable=False), - sa.Column("product_plan_uuid", sa.UUID(), nullable=False), - sa.Column("seats", sa.Integer(), nullable=True), - sa.Column("start_date", sa.DateTime(), nullable=False), - sa.Column("end_date", sa.DateTime(), nullable=False), - sa.Column("next_payment_date", sa.DateTime(), nullable=True), - sa.Column("voucher_uuid", sa.UUID(), nullable=True), - sa.Column("cancellation_date", sa.DateTime(), nullable=True), - sa.Column("created_at", sa.DateTime(), nullable=True), - sa.Column("updated_at", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint( - ["customer_uuid"], - ["customers.uuid"], - ), - sa.ForeignKeyConstraint( - ["product_plan_uuid"], - ["product_plans.uuid"], - ), - sa.ForeignKeyConstraint( - ["product_uuid"], - ["products.uuid"], - ), - sa.ForeignKeyConstraint( - ["voucher_uuid"], - ["vouchers.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - op.create_table( - "customer_product_contracts", - sa.Column("uuid", sa.UUID(), nullable=False), - sa.Column("product_customer_uuid", sa.UUID(), nullable=False), - sa.Column("contract_uuid", sa.UUID(), nullable=False), - sa.Column("accepted_at", sa.DateTime(), nullable=False), - sa.ForeignKeyConstraint( - ["contract_uuid"], - ["contracts.uuid"], - ), - sa.ForeignKeyConstraint( - ["product_customer_uuid"], - ["customer_products.uuid"], - ), - sa.PrimaryKeyConstraint("uuid"), - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table("customer_product_contracts") - op.drop_table("customer_products") - op.drop_table("vouchers") - op.drop_table("users") - op.drop_table("product_plans") - op.drop_table("product_contracts") - op.drop_table("messages") - op.drop_table("invoices") - op.drop_table("products") - op.drop_table("customers") - op.drop_table("contracts") - # ### end Alembic commands ### diff --git a/app/migrations/versions/9ce0def73b09_more_titles.py b/app/migrations/versions/9ce0def73b09_more_titles.py deleted file mode 100644 index 1a20fb2..0000000 --- a/app/migrations/versions/9ce0def73b09_more_titles.py +++ /dev/null @@ -1,37 +0,0 @@ -"""more titles - -Revision ID: 9ce0def73b09 -Revises: 8288ec79df35 -Create Date: 2025-04-16 09:33:48.300343 - -""" - -from typing import Sequence, Union - -import sqlalchemy as sa -from alembic import op - -# revision identifiers, used by Alembic. -revision: str = "9ce0def73b09" -down_revision: Union[str, None] = "8288ec79df35" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column("invoices", sa.Column("title", sa.String(), nullable=True)) - op.add_column( - "product_plans", - sa.Column( - "name", - sa.String(), - nullable=False)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column("product_plans", "name") - op.drop_column("invoices", "title") - # ### end Alembic commands ### diff --git a/app/models/customer_product.py b/app/models/customer_product.py index b0d3288..d85bbc1 100644 --- a/app/models/customer_product.py +++ b/app/models/customer_product.py @@ -2,14 +2,14 @@ from uuid import UUID as UUID4 from uuid import uuid4 +from models.product import ProductBase +from models.product_plan import ProductPlanBase from pydantic import BaseModel -from sqlalchemy import Column, DateTime, ForeignKey, Integer +from sqlalchemy import Column, DateTime, ForeignKey, Integer, Enum from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship - -from models.product import ProductBase -from models.product_plan import ProductPlanBase from utils.database.connection import Base +from models.static import CustomerProductStatusEnum class CustomerProduct(Base): @@ -25,6 +25,7 @@ class CustomerProduct(Base): product_plan_uuid = Column( UUID(as_uuid=True), ForeignKey("product_plans.uuid"), nullable=False ) + status = Column(Enum(CustomerProductStatusEnum), nullable=False) seats = Column(Integer, nullable=True) start_date = Column(DateTime, nullable=False) end_date = Column(DateTime, nullable=False) @@ -49,6 +50,7 @@ class CustomerProductBase(BaseModel): customer_uuid: UUID4 product_uuid: UUID4 product_plan_uuid: UUID4 + status: CustomerProductStatusEnum seats: int | None start_date: datetime next_payment_date: datetime | None @@ -63,6 +65,7 @@ class ExtendedCustomerProductBase(BaseModel): customer_uuid: UUID4 product: ProductBase product_plan: ProductPlanBase + status: CustomerProductStatusEnum seats: int | None start_date: datetime next_payment_date: datetime | None @@ -89,6 +92,7 @@ class CustomerProductCalculation(BaseModel): final_price: float before_price: float saving: float + tax: float = 0 class ProductCalculationResult(BaseModel): diff --git a/app/models/static.py b/app/models/static.py index 259167d..ad4da74 100644 --- a/app/models/static.py +++ b/app/models/static.py @@ -62,6 +62,17 @@ ) +class CustomerProductStatusEnum(PyEnum): + TRIALING = "trialing" + ACTIVE = "active" + PENDING_ACTIVATION = "pending_activation" + PENDING_PAYMENT = "pending_payment" + CANCELLATION_SCHEDULED = "cancellation_scheduled" + CANCELED = "canceled" + EXPIRED = "expired" + REFUNDED = "refunded" + + class RoleEnum(PyEnum): ADMIN = "admin" NORMAL = "normal" diff --git a/app/routers/customer_product.py b/app/routers/customer_product.py index a28033e..67eadab 100644 --- a/app/routers/customer_product.py +++ b/app/routers/customer_product.py @@ -3,7 +3,6 @@ from dateutil.relativedelta import relativedelta from fastapi import APIRouter, Body, Depends, HTTPException - from models.customer import User from models.customer_product import ( CustomerProduct, @@ -20,7 +19,7 @@ from models.product import Product from models.product_contract import ProductContract from models.product_plan import ProductPlan -from models.static import PlanTypeEnum +from models.static import CustomerProductStatusEnum, PlanTypeEnum from models.voucher import Voucher from utils.calculation.pricing import ( calculate_full_pricing_in_euro, @@ -99,6 +98,7 @@ async def create( product_uuid=data.product_uuid, product_plan_uuid=data.product_plan_uuid, voucher_uuid=data.voucher_uuid, + status=CustomerProductStatusEnum.PENDING_ACTIVATION, start_date=datetime.now(), end_date=( datetime.now() + relativedelta(months=+product_plan.recurring_month) @@ -133,9 +133,8 @@ async def create( @router.get("/{uuid}", response_model=CustomerProductBase) -async def read( - uuid: UUID, user: User = Depends(get_user), session=Depends(get_database) -): +async def read(uuid: UUID, user: User = Depends( + get_user), session=Depends(get_database)): customer_product = session.query( CustomerProduct).filter_by(uuid=uuid).first() @@ -164,6 +163,7 @@ async def calculate( seen_uuids = set() product_results: list[ProductCalculationResult] = [] total_final_price = 0 + total_taxes = 0 total_before_price = 0 total_saving = 0 @@ -197,17 +197,20 @@ async def calculate( final_price, before_price = calculate_full_pricing_in_euro( plan, voucher) saving = before_price - final_price + tax = 0.19 * final_price total_final_price += final_price total_before_price += before_price total_saving += saving + total_taxes += tax product_results.append(ProductCalculationResult( product_uuid=product_uuid, calculation=CustomerProductCalculation( final_price=final_price, before_price=before_price, - saving=saving + saving=saving, + tax=tax ) )) @@ -215,7 +218,8 @@ async def calculate( overall=CustomerProductCalculation( final_price=total_final_price, before_price=total_before_price, - saving=total_saving + saving=total_saving, + tax=total_taxes ), products=product_results ) @@ -232,5 +236,6 @@ async def delete( raise HTTPException(status_code=404, detail="Product not found.") customer_product.cancellation_date = datetime.now() + customer_product.status = CustomerProductStatusEnum.CANCELLATION_SCHEDULED, session.commit()