207 lines
7.0 KiB
Python
207 lines
7.0 KiB
Python
"""
|
||
Второй микросервис - Service 2
|
||
Предоставляет API для управления заказами и продуктами
|
||
"""
|
||
from fastapi import FastAPI, HTTPException
|
||
from pydantic import BaseModel
|
||
from typing import List, Optional
|
||
from datetime import datetime
|
||
import logging
|
||
|
||
app = FastAPI(
|
||
title="Service 2 - Order Service",
|
||
description="Микросервис для управления заказами и продуктами",
|
||
version="1.0.0"
|
||
)
|
||
|
||
# Логирование
|
||
logging.basicConfig(level=logging.INFO)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# Модели данных
|
||
class Product(BaseModel):
|
||
id: int
|
||
name: str
|
||
price: float
|
||
quantity: int
|
||
|
||
class ProductCreate(BaseModel):
|
||
name: str
|
||
price: float
|
||
quantity: int
|
||
|
||
class Order(BaseModel):
|
||
id: int
|
||
user_id: int
|
||
product_id: int
|
||
quantity: int
|
||
total_price: float
|
||
created_at: str
|
||
|
||
class OrderCreate(BaseModel):
|
||
user_id: int
|
||
product_id: int
|
||
quantity: int
|
||
|
||
# Имитация базы данных
|
||
products_db = {
|
||
1: {"id": 1, "name": "Ноутбук", "price": 50000.00, "quantity": 5},
|
||
2: {"id": 2, "name": "Монитор", "price": 15000.00, "quantity": 10},
|
||
3: {"id": 3, "name": "Клавиатура", "price": 3000.00, "quantity": 25},
|
||
}
|
||
|
||
orders_db = {
|
||
1: {
|
||
"id": 1,
|
||
"user_id": 1,
|
||
"product_id": 1,
|
||
"quantity": 1,
|
||
"total_price": 50000.00,
|
||
"created_at": "2025-01-01T10:00:00"
|
||
},
|
||
}
|
||
|
||
next_product_id = 4
|
||
next_order_id = 2
|
||
|
||
# Маршруты
|
||
@app.get("/", tags=["Health"])
|
||
async def root():
|
||
"""Проверка работоспособности Service 2"""
|
||
logger.info("Health check для Service 2")
|
||
return {
|
||
"service": "Service 2 - Order Service",
|
||
"status": "operational",
|
||
"version": "1.0.0"
|
||
}
|
||
|
||
@app.get("/health", tags=["Health"])
|
||
async def health_check():
|
||
"""Health check endpoint"""
|
||
return {"status": "healthy", "service": "order-service"}
|
||
|
||
# Endpoints для продуктов
|
||
@app.get("/products", response_model=List[Product], tags=["Products"])
|
||
async def list_products(skip: int = 0, limit: int = 10):
|
||
"""Получить список всех продуктов"""
|
||
logger.info(f"Получение списка продуктов (skip={skip}, limit={limit})")
|
||
products_list = list(products_db.values())
|
||
return products_list[skip:skip + limit]
|
||
|
||
@app.get("/products/{product_id}", response_model=Product, tags=["Products"])
|
||
async def get_product(product_id: int):
|
||
"""Получить продукт по ID"""
|
||
logger.info(f"Получение продукта с ID: {product_id}")
|
||
if product_id not in products_db:
|
||
logger.warning(f"Продукт с ID {product_id} не найден")
|
||
raise HTTPException(status_code=404, detail="Продукт не найден")
|
||
return products_db[product_id]
|
||
|
||
@app.post("/products", response_model=Product, tags=["Products"])
|
||
async def create_product(product: ProductCreate):
|
||
"""Создать новый продукт"""
|
||
global next_product_id
|
||
logger.info(f"Создание нового продукта: {product.name}")
|
||
|
||
new_product = {
|
||
"id": next_product_id,
|
||
"name": product.name,
|
||
"price": product.price,
|
||
"quantity": product.quantity
|
||
}
|
||
products_db[next_product_id] = new_product
|
||
next_product_id += 1
|
||
|
||
logger.info(f"Продукт создан с ID: {new_product['id']}")
|
||
return new_product
|
||
|
||
@app.put("/products/{product_id}", response_model=Product, tags=["Products"])
|
||
async def update_product(product_id: int, product: ProductCreate):
|
||
"""Обновить продукт"""
|
||
logger.info(f"Обновление продукта с ID: {product_id}")
|
||
if product_id not in products_db:
|
||
raise HTTPException(status_code=404, detail="Продукт не найден")
|
||
|
||
updated_product = {
|
||
"id": product_id,
|
||
"name": product.name,
|
||
"price": product.price,
|
||
"quantity": product.quantity
|
||
}
|
||
products_db[product_id] = updated_product
|
||
return updated_product
|
||
|
||
@app.delete("/products/{product_id}", tags=["Products"])
|
||
async def delete_product(product_id: int):
|
||
"""Удалить продукт"""
|
||
logger.info(f"Удаление продукта с ID: {product_id}")
|
||
if product_id not in products_db:
|
||
raise HTTPException(status_code=404, detail="Продукт не найден")
|
||
|
||
del products_db[product_id]
|
||
return {"message": f"Продукт {product_id} удален"}
|
||
|
||
# Endpoints для заказов
|
||
@app.get("/orders", response_model=List[Order], tags=["Orders"])
|
||
async def list_orders(skip: int = 0, limit: int = 10):
|
||
"""Получить список всех заказов"""
|
||
logger.info(f"Получение списка заказов (skip={skip}, limit={limit})")
|
||
orders_list = list(orders_db.values())
|
||
return orders_list[skip:skip + limit]
|
||
|
||
@app.get("/orders/{order_id}", response_model=Order, tags=["Orders"])
|
||
async def get_order(order_id: int):
|
||
"""Получить заказ по ID"""
|
||
logger.info(f"Получение заказа с ID: {order_id}")
|
||
if order_id not in orders_db:
|
||
logger.warning(f"Заказ с ID {order_id} не найден")
|
||
raise HTTPException(status_code=404, detail="Заказ не найден")
|
||
return orders_db[order_id]
|
||
|
||
@app.post("/orders", response_model=Order, tags=["Orders"])
|
||
async def create_order(order: OrderCreate):
|
||
"""Создать новый заказ"""
|
||
global next_order_id
|
||
logger.info(f"Создание нового заказа для пользователя {order.user_id}")
|
||
|
||
if order.product_id not in products_db:
|
||
raise HTTPException(status_code=404, detail="Продукт не найден")
|
||
|
||
product = products_db[order.product_id]
|
||
if product["quantity"] < order.quantity:
|
||
raise HTTPException(status_code=400, detail="Недостаточно товара на складе")
|
||
|
||
total_price = product["price"] * order.quantity
|
||
|
||
new_order = {
|
||
"id": next_order_id,
|
||
"user_id": order.user_id,
|
||
"product_id": order.product_id,
|
||
"quantity": order.quantity,
|
||
"total_price": total_price,
|
||
"created_at": datetime.utcnow().isoformat()
|
||
}
|
||
|
||
orders_db[next_order_id] = new_order
|
||
product["quantity"] -= order.quantity
|
||
next_order_id += 1
|
||
|
||
logger.info(f"Заказ создан с ID: {new_order['id']}")
|
||
return new_order
|
||
|
||
@app.get("/stats", tags=["Stats"])
|
||
async def get_stats():
|
||
"""Получить статистику по заказам"""
|
||
logger.info("Получение статистики")
|
||
total_revenue = sum(order["total_price"] for order in orders_db.values())
|
||
return {
|
||
"total_orders": len(orders_db),
|
||
"total_products": len(products_db),
|
||
"total_revenue": total_revenue,
|
||
"service": "order-service"
|
||
}
|
||
|
||
if __name__ == "__main__":
|
||
import uvicorn
|
||
uvicorn.run(app, host="0.0.0.0", port=8002)
|