updated to use 2 apis
This commit is contained in:
Binary file not shown.
@@ -1,2 +1,7 @@
|
|||||||
class UserAlreadyExists(Exception):
|
class UserAlreadyExists(Exception):
|
||||||
pass
|
pass
|
||||||
|
class OrderNotFound(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class OrderAlreadyExists(Exception):
|
||||||
|
pass
|
||||||
Binary file not shown.
23
src/application/ports/order_repository.py
Normal file
23
src/application/ports/order_repository.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from domain.orders import Order
|
||||||
|
|
||||||
|
class OrderRepository(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def save(self, order: Order):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def viewAll(self) -> list[Order]:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def viewById(self, order_id: int):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def removeOrder(self, order_id: int):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def editOrder(self, order_id: int, order: Order):
|
||||||
|
...
|
||||||
Binary file not shown.
68
src/application/services/order_services.py
Normal file
68
src/application/services/order_services.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from domain.orders import Order
|
||||||
|
from application.ports.order_repository import OrderRepository
|
||||||
|
|
||||||
|
class CreateOrder:
|
||||||
|
def __init__(self, repo: OrderRepository):
|
||||||
|
if not isinstance(repo, OrderRepository):
|
||||||
|
raise TypeError("repo must implement OrderRepository")
|
||||||
|
self.repo = repo
|
||||||
|
|
||||||
|
def execute(self, user_id: int, description: str, quantity: int, total_price: float):
|
||||||
|
from datetime import datetime
|
||||||
|
order = Order(
|
||||||
|
order_id=0,
|
||||||
|
user_id=user_id,
|
||||||
|
description=description,
|
||||||
|
quantity=quantity,
|
||||||
|
total_price=total_price,
|
||||||
|
created_at=datetime.now()
|
||||||
|
)
|
||||||
|
self.repo.save(order)
|
||||||
|
return order
|
||||||
|
|
||||||
|
class ViewOrders:
|
||||||
|
def __init__(self, repo: OrderRepository):
|
||||||
|
if not isinstance(repo, OrderRepository):
|
||||||
|
raise TypeError("repo must implement OrderRepository")
|
||||||
|
self.repo = repo
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
orders = self.repo.viewAll()
|
||||||
|
return orders
|
||||||
|
|
||||||
|
class ViewOrderById:
|
||||||
|
def __init__(self, repo: OrderRepository):
|
||||||
|
if not isinstance(repo, OrderRepository):
|
||||||
|
raise TypeError("repo must implement OrderRepository")
|
||||||
|
self.repo = repo
|
||||||
|
|
||||||
|
def execute(self, order_id: int) -> Order | None:
|
||||||
|
order = self.repo.viewById(order_id)
|
||||||
|
return order
|
||||||
|
|
||||||
|
class RemoveOrderById:
|
||||||
|
def __init__(self, repo: OrderRepository):
|
||||||
|
if not isinstance(repo, OrderRepository):
|
||||||
|
raise TypeError("repo must implement OrderRepository")
|
||||||
|
self.repo = repo
|
||||||
|
|
||||||
|
def execute(self, order_id: int) -> Order:
|
||||||
|
order = self.repo.removeOrder(order_id)
|
||||||
|
return {"Result": f"Order {order_id} deleted succesfully"}
|
||||||
|
|
||||||
|
class EditOrderById:
|
||||||
|
def __init__(self, repo: OrderRepository):
|
||||||
|
if not isinstance(repo, OrderRepository):
|
||||||
|
raise TypeError("repo must implement OrderRepository")
|
||||||
|
self.repo = repo
|
||||||
|
|
||||||
|
def execute(self, order_id: int, user_id: int, description: str, quantity: int, total_price: float) -> Order | None:
|
||||||
|
order = Order(
|
||||||
|
order_id=order_id,
|
||||||
|
user_id=user_id,
|
||||||
|
description=description,
|
||||||
|
quantity=quantity,
|
||||||
|
total_price=total_price,
|
||||||
|
created_at=None
|
||||||
|
)
|
||||||
|
return self.repo.editOrder(order_id, order)
|
||||||
BIN
src/domain/__pycache__/orders.cpython-314.pyc
Normal file
BIN
src/domain/__pycache__/orders.cpython-314.pyc
Normal file
Binary file not shown.
11
src/domain/orders.py
Normal file
11
src/domain/orders.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Order:
|
||||||
|
order_id: int
|
||||||
|
user_id: int
|
||||||
|
description: str
|
||||||
|
quantity: int
|
||||||
|
total_price: float
|
||||||
|
created_at: datetime
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Column, Integer, String
|
from sqlalchemy import Column, Integer, String, Float, DateTime
|
||||||
from infrastructure.adapters.persistence.db import Base
|
from infrastructure.adapters.persistence.db import Base
|
||||||
|
|
||||||
class UserModel(Base):
|
class UserModel(Base):
|
||||||
@@ -7,4 +7,14 @@ class UserModel(Base):
|
|||||||
user_id = Column(Integer, primary_key=True, index=True)
|
user_id = Column(Integer, primary_key=True, index=True)
|
||||||
name = Column(String, unique=False, index=True)
|
name = Column(String, unique=False, index=True)
|
||||||
email = Column(String, unique=True, index=True)
|
email = Column(String, unique=True, index=True)
|
||||||
phone = Column(String, unique=True, index=True)
|
phone = Column(String, unique=True, index=True)
|
||||||
|
|
||||||
|
class OrderModel(Base):
|
||||||
|
__tablename__ = "orders"
|
||||||
|
|
||||||
|
order_id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(Integer, index=True)
|
||||||
|
description = Column(String, index=True)
|
||||||
|
quantity = Column(Integer, index=True)
|
||||||
|
total_price = Column(Float, index=True)
|
||||||
|
created_at = Column(DateTime, index=True)
|
||||||
|
|||||||
108
src/infrastructure/adapters/persistence/order_repository_sql.py
Normal file
108
src/infrastructure/adapters/persistence/order_repository_sql.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
from domain.orders import Order
|
||||||
|
from application.ports.order_repository import OrderRepository
|
||||||
|
from infrastructure.adapters.persistence.db import SessionLocal
|
||||||
|
from infrastructure.adapters.persistence.models import OrderModel
|
||||||
|
|
||||||
|
class SqlOrderRepository(OrderRepository):
|
||||||
|
def __init__(self):
|
||||||
|
self.db: Session = SessionLocal()
|
||||||
|
|
||||||
|
def save(self, order: Order):
|
||||||
|
model = OrderModel(
|
||||||
|
user_id=order.user_id,
|
||||||
|
description=order.description,
|
||||||
|
quantity=order.quantity,
|
||||||
|
total_price=order.total_price,
|
||||||
|
created_at=order.created_at
|
||||||
|
)
|
||||||
|
|
||||||
|
self.db.add(model)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.db.commit()
|
||||||
|
except IntegrityError:
|
||||||
|
self.db.rollback()
|
||||||
|
raise Exception("An error occurred while creating the order.")
|
||||||
|
|
||||||
|
self.db.refresh(model)
|
||||||
|
|
||||||
|
return Order(
|
||||||
|
order_id=model.order_id,
|
||||||
|
user_id=model.user_id,
|
||||||
|
description=model.description,
|
||||||
|
quantity=model.quantity,
|
||||||
|
total_price=model.total_price,
|
||||||
|
created_at=model.created_at
|
||||||
|
)
|
||||||
|
|
||||||
|
def viewAll(self) -> list[Order]:
|
||||||
|
models = self.db.query(OrderModel).all()
|
||||||
|
|
||||||
|
return [
|
||||||
|
Order(
|
||||||
|
order_id=model.order_id,
|
||||||
|
user_id=model.user_id,
|
||||||
|
description=model.description,
|
||||||
|
quantity=model.quantity,
|
||||||
|
total_price=model.total_price,
|
||||||
|
created_at=model.created_at
|
||||||
|
) for model in models
|
||||||
|
]
|
||||||
|
|
||||||
|
def viewById(self, order_id: int) -> Order | None:
|
||||||
|
model = self.db.query(OrderModel).filter(OrderModel.order_id == order_id).first()
|
||||||
|
|
||||||
|
if not model:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return Order(
|
||||||
|
order_id=model.order_id,
|
||||||
|
user_id=model.user_id,
|
||||||
|
description=model.description,
|
||||||
|
quantity=model.quantity,
|
||||||
|
total_price=model.total_price,
|
||||||
|
created_at=model.created_at
|
||||||
|
)
|
||||||
|
|
||||||
|
def removeOrder(self, order_id: int):
|
||||||
|
model = self.db.query(OrderModel).filter(OrderModel.order_id == order_id).first()
|
||||||
|
|
||||||
|
if not model:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.db.delete(model)
|
||||||
|
self.db.commit()
|
||||||
|
return True
|
||||||
|
except IntegrityError:
|
||||||
|
self.db.rollback()
|
||||||
|
raise Exception("Cannot delete order due to existing references.")
|
||||||
|
|
||||||
|
def editOrder(self, order_id: int, order: Order) -> Order | None:
|
||||||
|
model = self.db.query(OrderModel).filter(OrderModel.order_id == order_id).first()
|
||||||
|
|
||||||
|
if not model:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
model.user_id = order.user_id
|
||||||
|
model.description = order.description
|
||||||
|
model.quantity = order.quantity
|
||||||
|
model.total_price = order.total_price
|
||||||
|
|
||||||
|
self.db.commit()
|
||||||
|
self.db.refresh(model)
|
||||||
|
|
||||||
|
return Order(
|
||||||
|
order_id=model.order_id,
|
||||||
|
user_id=model.user_id,
|
||||||
|
description=model.description,
|
||||||
|
quantity=model.quantity,
|
||||||
|
total_price=model.total_price,
|
||||||
|
created_at=model.created_at
|
||||||
|
)
|
||||||
|
except IntegrityError:
|
||||||
|
self.db.rollback()
|
||||||
|
raise Exception("An error occurred while updating the order.")
|
||||||
0
src/infrastructure/api/orders/__init__.py
Normal file
0
src/infrastructure/api/orders/__init__.py
Normal file
Binary file not shown.
BIN
src/infrastructure/api/orders/__pycache__/app.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/orders/__pycache__/app.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/orders/__pycache__/orders.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/orders/__pycache__/orders.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/orders/__pycache__/root.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/orders/__pycache__/root.cpython-314.pyc
Normal file
Binary file not shown.
BIN
src/infrastructure/api/orders/__pycache__/router.cpython-314.pyc
Normal file
BIN
src/infrastructure/api/orders/__pycache__/router.cpython-314.pyc
Normal file
Binary file not shown.
10
src/infrastructure/api/orders/app.py
Normal file
10
src/infrastructure/api/orders/app.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from core.config import ConfSettings
|
||||||
|
from infrastructure.api.orders.router import router
|
||||||
|
|
||||||
|
def create_app() -> FastAPI:
|
||||||
|
app = FastAPI(title="Orders Microservice",
|
||||||
|
version="1.0.0",
|
||||||
|
description="Microservicio de gestión de pedidos")
|
||||||
|
app.include_router(router)
|
||||||
|
return app
|
||||||
77
src/infrastructure/api/orders/orders.py
Normal file
77
src/infrastructure/api/orders/orders.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from application.services.order_services import CreateOrder, ViewOrders, ViewOrderById, RemoveOrderById, EditOrderById
|
||||||
|
from infrastructure.adapters.persistence.order_repository_sql import SqlOrderRepository
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/")
|
||||||
|
def create_order(user_id: int, description: str, quantity: int, total_price: float):
|
||||||
|
service = CreateOrder(SqlOrderRepository())
|
||||||
|
|
||||||
|
try:
|
||||||
|
return service.execute(user_id, description, quantity, total_price)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
def view_all_orders():
|
||||||
|
service = ViewOrders(SqlOrderRepository())
|
||||||
|
|
||||||
|
try:
|
||||||
|
return service.execute()
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/{order_id}")
|
||||||
|
def view_order_by_id(order_id: int):
|
||||||
|
service = ViewOrderById(SqlOrderRepository())
|
||||||
|
|
||||||
|
result = service.execute(order_id)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Order not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@router.delete("/{order_id}")
|
||||||
|
def delete_order_by_id(order_id: int):
|
||||||
|
service = RemoveOrderById(SqlOrderRepository())
|
||||||
|
|
||||||
|
result = service.execute(order_id)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Order not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@router.put("/{order_id}")
|
||||||
|
def edit_order_by_id(order_id: int, user_id: int, description: str, quantity: int, total_price: float):
|
||||||
|
service = EditOrderById(SqlOrderRepository())
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = service.execute(order_id=order_id, user_id=user_id, description=description, quantity=quantity, total_price=total_price)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Order not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
16
src/infrastructure/api/orders/root.py
Normal file
16
src/infrastructure/api/orders/root.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
import platform
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
def root():
|
||||||
|
uname = platform.uname()
|
||||||
|
return {
|
||||||
|
"machine": {
|
||||||
|
"OS": f"{uname.system} {uname.release}",
|
||||||
|
"Arch": uname.machine
|
||||||
|
},
|
||||||
|
"Status": "Running",
|
||||||
|
"Docs": "/docs"
|
||||||
|
}
|
||||||
17
src/infrastructure/api/orders/router.py
Normal file
17
src/infrastructure/api/orders/router.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
from infrastructure.api.orders.orders import router as orders_router
|
||||||
|
from infrastructure.api.orders.root import router as root_router
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
router.include_router(
|
||||||
|
orders_router,
|
||||||
|
prefix="/orders",
|
||||||
|
tags=["orders"]
|
||||||
|
)
|
||||||
|
|
||||||
|
router.include_router(
|
||||||
|
root_router,
|
||||||
|
prefix='',
|
||||||
|
tags=["root"]
|
||||||
|
)
|
||||||
51
src/main.py
51
src/main.py
@@ -1,17 +1,52 @@
|
|||||||
from infrastructure.api.users.app import create_app
|
from infrastructure.api.users.app import create_app as create_users_app
|
||||||
|
from infrastructure.api.orders.app import create_app as create_orders_app
|
||||||
from core.config import ConfSettings
|
from core.config import ConfSettings
|
||||||
|
import threading
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
app = create_app()
|
def run_users_api():
|
||||||
|
"""Ejecuta la API de usuarios en puerto 8000"""
|
||||||
def run():
|
app_users = create_users_app()
|
||||||
import uvicorn
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"main:app",
|
app_users,
|
||||||
host=ConfSettings.host,
|
host=ConfSettings.host,
|
||||||
port=ConfSettings.port,
|
port=8000,
|
||||||
reload=ConfSettings.reload,
|
reload=False,
|
||||||
log_level=ConfSettings.log_level,
|
log_level=ConfSettings.log_level,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def run_orders_api():
|
||||||
|
"""Ejecuta la API de pedidos en puerto 8001"""
|
||||||
|
app_orders = create_orders_app()
|
||||||
|
uvicorn.run(
|
||||||
|
app_orders,
|
||||||
|
host=ConfSettings.host,
|
||||||
|
port=8001,
|
||||||
|
reload=False,
|
||||||
|
log_level=ConfSettings.log_level,
|
||||||
|
)
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""Inicia ambas APIs en threads separados"""
|
||||||
|
print("Iniciando microservicios...")
|
||||||
|
|
||||||
|
users_thread = threading.Thread(target=run_users_api, daemon=True, name="Users-API")
|
||||||
|
orders_thread = threading.Thread(target=run_orders_api, daemon=True, name="Orders-API")
|
||||||
|
|
||||||
|
users_thread.start()
|
||||||
|
orders_thread.start()
|
||||||
|
|
||||||
|
print("✓ API de Usuarios ejecutándose en http://0.0.0.0:8000")
|
||||||
|
print("✓ API de Pedidos ejecutándose en http://0.0.0.0:8001")
|
||||||
|
print("\nDocumentación disponible en:")
|
||||||
|
print(" - Usuarios: http://localhost:8000/docs")
|
||||||
|
print(" - Pedidos: http://localhost:8001/docs")
|
||||||
|
|
||||||
|
try:
|
||||||
|
users_thread.join()
|
||||||
|
orders_thread.join()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n\nAteniendo señal de salida...")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
17
src/main_orders.py
Normal file
17
src/main_orders.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from infrastructure.api.orders.app import create_app
|
||||||
|
from core.config import ConfSettings
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
def run():
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(
|
||||||
|
"main_orders:app",
|
||||||
|
host=ConfSettings.host,
|
||||||
|
port=8001,
|
||||||
|
reload=ConfSettings.reload,
|
||||||
|
log_level=ConfSettings.log_level,
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run()
|
||||||
BIN
src/users.db
BIN
src/users.db
Binary file not shown.
Reference in New Issue
Block a user