Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse
from sqlalchemy.exc import OperationalError

from routers.contract import router as contract_router
from routers.customer import router as customer_router
from routers.customer_product import router as customer_product_router
from routers.invoice import router as invoice_router
from routers.product import router as product_router
from routers.voucher import router as voucher_router
from sqlalchemy.exc import OperationalError
from utils.config import keycloak_openid, settings
from utils.database.connection import engine
from utils.helpers.example import create_example_data
Expand Down
1 change: 1 addition & 0 deletions app/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from alembic import context
from sqlalchemy import engine_from_config, pool

from utils.database.connection import SQLALCHEMY_DATABASE_URL, Base

# this is the Alembic Config object, which provides
Expand Down
5 changes: 3 additions & 2 deletions app/models/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
from uuid import UUID as UUID4
from uuid import uuid4

from models.product_contract import ProductContract
from models.static import ContractKeyEnum
from pydantic import BaseModel
from sqlalchemy import Column, DateTime, Enum, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.product_contract import ProductContract
from models.static import ContractKeyEnum
from utils.database.connection import Base


Expand Down
9 changes: 5 additions & 4 deletions app/models/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
from uuid import UUID as UUID4
from uuid import uuid4

from pydantic import BaseModel
from sqlalchemy import Column, DateTime, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.customer_product import CustomerProduct
from models.invoice import Invoice
from models.message import Message
from models.static import HouseNumber, Mail, PhoneNumber, PostalCode, WebURL
from models.user import User
from pydantic import BaseModel
from sqlalchemy import Column, DateTime, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from utils.database.connection import Base


Expand Down
15 changes: 13 additions & 2 deletions app/models/customer_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
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.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


Expand Down Expand Up @@ -88,3 +89,13 @@ class CustomerProductCalculation(BaseModel):
final_price: float
before_price: float
saving: float


class ProductCalculationResult(BaseModel):
product_uuid: UUID4
calculation: CustomerProductCalculation


class CustomerProductsCalculation(BaseModel):
overall: CustomerProductCalculation
products: list[ProductCalculationResult]
1 change: 1 addition & 0 deletions app/models/customer_product_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from sqlalchemy import Column, DateTime, ForeignKey
from sqlalchemy.dialects.postgresql import UUID

from utils.database.connection import Base


Expand Down
3 changes: 2 additions & 1 deletion app/models/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from uuid import UUID as UUID4
from uuid import uuid4

from models.static import InvoiceStatusEnum
from pydantic import BaseModel
from sqlalchemy import Column, DateTime, Enum, ForeignKey, Numeric, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.static import InvoiceStatusEnum
from utils.database.connection import Base


Expand Down
3 changes: 2 additions & 1 deletion app/models/message.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from datetime import datetime
from uuid import uuid4

from models.static import MessageStatusEnum
from sqlalchemy import Column, DateTime, Enum, ForeignKey, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.static import MessageStatusEnum
from utils.database.connection import Base


Expand Down
5 changes: 3 additions & 2 deletions app/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
from uuid import UUID as UUID4
from uuid import uuid4

from models.product_contract import ProductContract
from models.product_plan import ProductPlan, ProductPlanBase
from pydantic import BaseModel
from sqlalchemy import Column, DateTime, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.product_contract import ProductContract
from models.product_plan import ProductPlan, ProductPlanBase
from utils.database.connection import Base


Expand Down
1 change: 1 addition & 0 deletions app/models/product_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from sqlalchemy import Column, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from utils.database.connection import Base


Expand Down
3 changes: 2 additions & 1 deletion app/models/product_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from uuid import UUID as UUID4
from uuid import uuid4

from models.static import PlanTypeEnum
from pydantic import BaseModel
from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, Numeric, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.static import PlanTypeEnum
from utils.database.connection import Base


Expand Down
3 changes: 2 additions & 1 deletion app/models/user.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from datetime import datetime
from uuid import uuid4

from models.static import RoleEnum
from sqlalchemy import Column, DateTime, Enum, ForeignKey, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from models.static import RoleEnum
from utils.database.connection import Base


Expand Down
1 change: 1 addition & 0 deletions app/models/voucher.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from sqlalchemy import Column, DateTime, ForeignKey, Integer, Numeric, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from utils.database.connection import Base


Expand Down
1 change: 1 addition & 0 deletions app/routers/contract.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException

from models.contract import Contract, ContractBase, ContractsByProductRead
from models.product_contract import ProductContract
from utils.database.session import get_database
Expand Down
1 change: 1 addition & 0 deletions app/routers/customer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException

from models.customer import Customer, CustomerBase, CustomerUpdate, User
from models.static import RoleEnum
from utils.database.session import get_database
Expand Down
100 changes: 70 additions & 30 deletions app/routers/customer_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
from uuid import UUID

from dateutil.relativedelta import relativedelta
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Body, Depends, HTTPException

from models.customer import User
from models.customer_product import (
CustomerProduct,
CustomerProductBase,
CustomerProductCalculation,
CustomerProductCalculationRequest,
CustomerProductCreate,
CustomerProductsCalculation,
ExtendedCustomerProductBase,
ProductCalculationResult,
)
from models.customer_product_contract import CustomerProductContract
from models.invoice import Invoice
Expand Down Expand Up @@ -150,35 +153,72 @@ async def read_all_by_customer(user: User = Depends(get_user)):
return user.customer.products


@router.post("/calculate/", response_model=CustomerProductCalculation)
async def calculate(data: CustomerProductCalculationRequest,
session=Depends(get_database)):
product = session.query(Product).filter_by(uuid=data.product_uuid).first()

if not product:
raise HTTPException(status_code=404, detail="Product not found.")

product_plan = session.query(ProductPlan).filter_by(
uuid=data.product_plan_uuid).first()

if not product_plan or product_plan.product.uuid != product.uuid:
raise HTTPException(404, detail="Plan does not exist on that product.")

voucher = None

if data.voucher_uuid:
voucher = session.query(Voucher).filter_by(
uuid=data.voucher_uuid).first()

if not voucher or not voucher.valid or voucher.product_plan != product_plan.uuid:
raise HTTPException(404, detail="Voucher not valid.")

final_price, before_price = calculate_full_pricing_in_euro(
product_plan, voucher)
saving = before_price - final_price

return {"final_price": final_price,
"before_price": before_price, "saving": saving}
@router.post("/calculate/", response_model=CustomerProductsCalculation)
async def calculate(
products: list[CustomerProductCalculationRequest] = Body(
...,
description="List of product calculation requests. Each must have a unique product_uuid."
),
session=Depends(get_database)
):
seen_uuids = set()
product_results: list[ProductCalculationResult] = []
total_final_price = 0
total_before_price = 0
total_saving = 0

for request_data in products:
product_uuid = request_data.product_uuid

if product_uuid in seen_uuids:
raise HTTPException(
status_code=400,
detail=f"Duplicate product_uuid: {product_uuid}")
seen_uuids.add(product_uuid)

product = session.query(Product).filter_by(uuid=product_uuid).first()
if not product:
raise HTTPException(status_code=404, detail="Product not found.")

plan = session.query(ProductPlan).filter_by(
uuid=request_data.product_plan_uuid).first()
if not plan or plan.product.uuid != product.uuid:
raise HTTPException(status_code=404,
detail="Plan does not exist on that product.")

voucher = None
if request_data.voucher_uuid:
voucher = session.query(Voucher).filter_by(
uuid=request_data.voucher_uuid).first()
if not voucher or not voucher.valid or voucher.product_plan != plan.uuid:
raise HTTPException(
status_code=404, detail="Voucher not valid.")

final_price, before_price = calculate_full_pricing_in_euro(
plan, voucher)
saving = before_price - final_price

total_final_price += final_price
total_before_price += before_price
total_saving += saving

product_results.append(ProductCalculationResult(
product_uuid=product_uuid,
calculation=CustomerProductCalculation(
final_price=final_price,
before_price=before_price,
saving=saving
)
))

return CustomerProductsCalculation(
overall=CustomerProductCalculation(
final_price=total_final_price,
before_price=total_before_price,
saving=total_saving
),
products=product_results
)


@router.delete("/{uuid}")
Expand Down
1 change: 1 addition & 0 deletions app/routers/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import stripe
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Request

from models.invoice import Invoice, InvoiceBase, InvoicePayRequest, InvoiceStatusEnum
from models.user import User
from utils.config import settings, stripe_return_url
Expand Down
1 change: 1 addition & 0 deletions app/routers/product.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException

from models.customer_product import CustomerProduct
from models.product import Product, ProductBase
from models.user import User
Expand Down
1 change: 1 addition & 0 deletions app/routers/voucher.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException

from models.voucher import Voucher, VoucherBase
from utils.database.session import get_database

Expand Down
1 change: 1 addition & 0 deletions app/utils/database/connection.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

from utils.config import settings

SQLALCHEMY_DATABASE_URL = (
Expand Down
1 change: 1 addition & 0 deletions app/utils/database/session.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from sqlalchemy.orm import Session

from utils.database.connection import SessionLocal


Expand Down
3 changes: 2 additions & 1 deletion app/utils/security/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from keycloak.exceptions import KeycloakAuthenticationError, KeycloakPostError
from models.user import User
from pydantic import BaseModel

from models.user import User
from utils.config import keycloak_openid
from utils.database.session import get_database

Expand Down
Loading