added create order

parent b36c3b33
from tortoise.exceptions import ValidationError
from ..base import BaseController
from .services import OrderService
from exceptions import common as common_exc, http as http_exc
class OrderController(BaseController):
order_service = OrderService()
async def create(self, **kwargs):
try:
return await self.order_service.create_order(**kwargs)
except common_exc.CreateException as e:
raise http_exc.HTTPBadRequestException(detail=str(e))
except ValidationError as e:
raise http_exc.HTTPBadRequestException(detail=f"Validation error: {str(e)}")
import fastapi as fa
from .ctrl import OrderController
from .schemas import OrderPostSchema
router = fa.APIRouter(prefix='/orders', tags=['Order'])
ctrl = OrderController()
@router.post('')
async def create_order(body: OrderPostSchema):
return await ctrl.create(**body.model_dump(exclude_none=True))
from typing import List
from uuid import UUID
from pydantic import BaseModel, ConfigDict
from api.product.schemas import ProductPostSchema, ProductOrderGetSchema
class OrderBaseSchema(BaseModel):
name: str | None = None
class OrderIdSchema(BaseModel):
id: UUID
model_config = ConfigDict(from_attributes=True)
class OrderPostSchema(BaseModel):
items: List[ProductPostSchema]
class OrderGetSchema(OrderIdSchema):
status: str
total: float
products: List[ProductOrderGetSchema]
from db.repositories.order import OrderRepository
from db.repositories.product import ProductRepository
from .schemas import OrderGetSchema
from exceptions import common as common_exc, http as http_exc
from db.models import ProductOrder
class OrderService:
order_repository = OrderRepository()
product_repository = ProductRepository()
async def create_order(self, **kwargs):
total = 0
order = await self.order_repository.create(**kwargs)
order_products = []
for item in kwargs.get('items'):
try:
product = await self.product_repository.get(id=item['id'])
except common_exc.NotFoundException:
raise http_exc.HTTPBadRequestException(detail='Object product does not exist')
quantity = item['quantity']
await ProductOrder.create(order=order, product=product, quantity=quantity)
total += product.price * quantity
order_products.append({"id": product.id, "price": product.price, "quantity": quantity})
order.total = total
await order.save()
order_data = {
"id": order.id,
"status": order.status,
"total": order.total,
"products": order_products
}
return OrderGetSchema.model_validate(order_data)
...@@ -16,3 +16,14 @@ class ProductGetSchema(ProductBaseSchema, ProductIdSchema): ...@@ -16,3 +16,14 @@ class ProductGetSchema(ProductBaseSchema, ProductIdSchema):
description: str | None = None description: str | None = None
price: float | None = None price: float | None = None
image: str | None = None image: str | None = None
class ProductPostSchema(BaseModel):
id: UUID
quantity: int
class ProductOrderGetSchema(BaseModel):
id: UUID
price: int
quantity: int
from fastapi import APIRouter from fastapi import APIRouter
from .product.routes import router as product_route from .product.routes import router as product_route
from .order.routes import router as order_route
router = APIRouter(prefix='/api') router = APIRouter(prefix='/api')
router.include_router(product_route) router.include_router(product_route)
router.include_router(order_route)
from tortoise import fields from enum import Enum
from tortoise import fields, models
from .base import BaseModel from .base import BaseModel
...@@ -14,3 +16,32 @@ class Product(BaseModel): ...@@ -14,3 +16,32 @@ class Product(BaseModel):
class Meta(BaseModel.Meta): class Meta(BaseModel.Meta):
table = 'products' table = 'products'
class Order(BaseModel):
class StatusEnum(str, Enum):
IN_PROCESSING = 'IN_PROCESSING'
CONFIRMED = 'CONFIRMED'
COMPLETED = 'COMPLETED'
products = fields.ManyToManyField(
'models.Product', related_name='order_products',
through='products_orders'
)
status = fields.CharEnumField(enum_type=StatusEnum, default=StatusEnum.IN_PROCESSING)
total = fields.DecimalField(max_digits=10, decimal_places=2, default=0.0)
def __str__(self):
return f'Order #{self.id}'
class Meta(BaseModel.Meta):
table = 'orders'
class ProductOrder(models.Model):
order = fields.ForeignKeyField('models.Order', related_name='order_products')
product = fields.ForeignKeyField('models.Product', related_name='product_orders')
quantity = fields.IntField(default=1)
class Meta(BaseModel.Meta):
table = 'products_orders'
from .base import BaseRepository
from ..models import Order
class OrderRepository(BaseRepository):
model = Order
...@@ -8,15 +8,29 @@ async def upgrade(db: BaseDBAsyncClient) -> str: ...@@ -8,15 +8,29 @@ async def upgrade(db: BaseDBAsyncClient) -> str:
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP "updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
); );
CREATE TABLE IF NOT EXISTS "orders" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"status" VARCHAR(13) NOT NULL DEFAULT 'IN_PROCESSING',
"total" DECIMAL(10,2) NOT NULL DEFAULT 0
);
COMMENT ON COLUMN "orders"."status" IS 'IN_PROCESSING: IN_PROCESSING\nCONFIRMED: CONFIRMED\nCOMPLETED: COMPLETED';
CREATE TABLE IF NOT EXISTS "products" ( CREATE TABLE IF NOT EXISTS "products" (
"id" UUID NOT NULL PRIMARY KEY, "id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" VARCHAR(255) NOT NULL, "name" VARCHAR(255) NOT NULL,
"description" TEXT NOT NULL, "description" TEXT,
"price" DOUBLE PRECISION NOT NULL, "price" DOUBLE PRECISION NOT NULL,
"image" TEXT NOT NULL "image" TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS "products_orders" (
"id" SERIAL NOT NULL PRIMARY KEY,
"quantity" INT NOT NULL DEFAULT 1,
"order_id" UUID NOT NULL REFERENCES "orders" ("id") ON DELETE CASCADE,
"product_id" UUID NOT NULL REFERENCES "products" ("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "aerich" ( CREATE TABLE IF NOT EXISTS "aerich" (
"id" SERIAL NOT NULL PRIMARY KEY, "id" SERIAL NOT NULL PRIMARY KEY,
"version" VARCHAR(255) NOT NULL, "version" VARCHAR(255) NOT NULL,
......
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "products" ALTER COLUMN "description" DROP NOT NULL;"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "products" ALTER COLUMN "description" SET NOT NULL;"""
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment