aboutsummaryrefslogtreecommitdiff
path: root/order-service/app
diff options
context:
space:
mode:
authoralex <[email protected]>2026-07-15 20:24:31 +0200
committeralex <[email protected]>2026-07-15 20:24:31 +0200
commit8e12cb9bb66adc7adaf6d276133d6f235d294d23 (patch)
tree31aa3f6a06407b39bb23d7cc724c70899795a788 /order-service/app
downloadorder-inventory-system-8e12cb9bb66adc7adaf6d276133d6f235d294d23.tar.xz
order-inventory-system-8e12cb9bb66adc7adaf6d276133d6f235d294d23.zip
init
Diffstat (limited to 'order-service/app')
-rw-r--r--order-service/app/api/deps.py10
-rw-r--r--order-service/app/api/v1/api.py5
-rw-r--r--order-service/app/api/v1/endpoints/orders.py48
-rw-r--r--order-service/app/core/config.py14
-rw-r--r--order-service/app/core/database.py8
-rw-r--r--order-service/app/init_db.py13
-rw-r--r--order-service/app/main.py19
-rw-r--r--order-service/app/models/order.py41
-rw-r--r--order-service/app/schemas/order.py36
9 files changed, 194 insertions, 0 deletions
diff --git a/order-service/app/api/deps.py b/order-service/app/api/deps.py
new file mode 100644
index 0000000..d8dd349
--- /dev/null
+++ b/order-service/app/api/deps.py
@@ -0,0 +1,10 @@
+from typing import Generator
+from app.core.database import SessionLocal
+
+
+def get_db() -> Generator:
+ db = SessionLocal()
+ try:
+ yield db
+ finally:
+ db.close()
diff --git a/order-service/app/api/v1/api.py b/order-service/app/api/v1/api.py
new file mode 100644
index 0000000..a967cb4
--- /dev/null
+++ b/order-service/app/api/v1/api.py
@@ -0,0 +1,5 @@
+from fastapi import APIRouter
+from app.api.v1.endpoints import orders
+
+api_router = APIRouter()
+api_router.include_router(orders.router, prefix="/orders", tags=["orders"])
diff --git a/order-service/app/api/v1/endpoints/orders.py b/order-service/app/api/v1/endpoints/orders.py
new file mode 100644
index 0000000..4530958
--- /dev/null
+++ b/order-service/app/api/v1/endpoints/orders.py
@@ -0,0 +1,48 @@
+from decimal import Decimal
+from fastapi import APIRouter, Depends, HTTPException, status
+from sqlalchemy.orm import Session
+
+from app.api import deps
+from app.models.order import Order, OrderItem
+from app.schemas.order import OrderCreate, OrderOut
+
+router = APIRouter()
+
+
[email protected]("/", response_model=OrderOut, status_code=status.HTTP_202_ACCEPTED)
+def create_order(order_in: OrderCreate, db: Session = Depends(deps.get_db)):
+ """
+ Submit a new customer order.
+ Returns status code 202 (Accepted) as the order is pending verification.
+ """
+ try:
+ total = Decimal("0.00")
+ for item in order_in.items:
+ total += item.price * item.quantity
+
+ db_order = Order(
+ customer_id=order_in.customer_id, status="PENDING", total_price=total
+ )
+ db.add(db_order)
+ db.flush()
+
+ for item in order_in.items:
+ db_item = OrderItem(
+ order_id=db_order.id,
+ product_id=item.product_id,
+ quantity=item.quantity,
+ price=item.price,
+ )
+ db.add(db_item)
+
+ db.commit()
+ db.refresh(db_order)
+
+ return db_order
+
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail="Could not initialize checkout process.",
+ )
diff --git a/order-service/app/core/config.py b/order-service/app/core/config.py
new file mode 100644
index 0000000..013b356
--- /dev/null
+++ b/order-service/app/core/config.py
@@ -0,0 +1,14 @@
+from pydantic_settings import BaseSettings
+
+
+class Settings(BaseSettings):
+ PROJECT_NAME: str = "Order Service API"
+
+ DATABASE_URL: str
+
+ class Config:
+ env_file = ".env"
+ env_file_encoding = "utf-8"
+
+
+settings = Settings()
diff --git a/order-service/app/core/database.py b/order-service/app/core/database.py
new file mode 100644
index 0000000..55d3e82
--- /dev/null
+++ b/order-service/app/core/database.py
@@ -0,0 +1,8 @@
+from sqlalchemy import create_engine
+from sqlalchemy.orm import declarative_base, sessionmaker
+from app.core.config import settings
+
+engine = create_engine(settings.DATABASE_URL)
+SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
+
+Base = declarative_base() \ No newline at end of file
diff --git a/order-service/app/init_db.py b/order-service/app/init_db.py
new file mode 100644
index 0000000..7ee1465
--- /dev/null
+++ b/order-service/app/init_db.py
@@ -0,0 +1,13 @@
+from app.core.database import engine, Base
+
+from app.models.order import Order, OrderItem
+
+
+def init_database():
+ print("Creating database tables...")
+ Base.metadata.create_all(bind=engine)
+ print("Database initialized successfully! 🎉")
+
+
+if __name__ == "__main__":
+ init_database()
diff --git a/order-service/app/main.py b/order-service/app/main.py
new file mode 100644
index 0000000..7837f11
--- /dev/null
+++ b/order-service/app/main.py
@@ -0,0 +1,19 @@
+import uvicorn
+from fastapi import FastAPI
+from app.api.v1.api import api_router
+from app.core.config import settings
+
+app = FastAPI(
+ title=settings.PROJECT_NAME,
+)
+
+app.include_router(api_router, prefix="/api/v1")
+
+
+def health_check():
+ return {"status": "working"}
+
+
+if __name__ == "__main__":
+ uvicorn.run("app.main:app", host="127.0.0.1", port=8000, reload=True)
diff --git a/order-service/app/models/order.py b/order-service/app/models/order.py
new file mode 100644
index 0000000..1111269
--- /dev/null
+++ b/order-service/app/models/order.py
@@ -0,0 +1,41 @@
+from sqlalchemy import Column, Integer, Numeric, String, DateTime, ForeignKey
+from sqlalchemy.orm import relationship
+from sqlalchemy.sql import func
+from app.core.database import Base
+
+
+class Order(Base):
+ __tablename__ = "orders"
+
+ id = Column(Integer, primary_key=True, index=True)
+ customer_id = Column(Integer, nullable=False, index=True)
+ status = Column(String(20), default="PENDING", nullable=False)
+ total_price = Column(Numeric(10, 2), nullable=False)
+
+ created_at = Column(
+ DateTime(timezone=True), server_default=func.now(), nullable=False
+ )
+ updated_at = Column(
+ DateTime(timezone=True),
+ server_default=func.now(),
+ onupdate=func.now(),
+ nullable=False,
+ )
+
+ items = relationship(
+ "OrderItem", back_populates="order", cascade="all, delete-orphan"
+ )
+
+
+class OrderItem(Base):
+ __tablename__ = "order_items"
+
+ id = Column(Integer, primary_key=True, index=True)
+ order_id = Column(
+ Integer, ForeignKey("orders.id", ondelete="CASCADE"), nullable=False
+ )
+ product_id = Column(Integer, nullable=False)
+ quantity = Column(Integer, nullable=False)
+ price = Column(Numeric(10, 2), nullable=False)
+
+ order = relationship("Order", back_populates="items")
diff --git a/order-service/app/schemas/order.py b/order-service/app/schemas/order.py
new file mode 100644
index 0000000..47aff2c
--- /dev/null
+++ b/order-service/app/schemas/order.py
@@ -0,0 +1,36 @@
+from datetime import datetime
+from decimal import Decimal
+from pydantic import BaseModel, Field, ConfigDict
+
+
+class OrderItemCreate(BaseModel):
+ product_id: int = Field(..., gt=0, description="Database ID of the product")
+ quantity: int = Field(..., gt=0, le=100, description="Must buy at least 1, max 100")
+ price: Decimal = Field(..., gt=0.00, description="The price per unit")
+
+
+class OrderItemOut(BaseModel):
+ id: int
+ product_id: int
+ quantity: int
+ price: Decimal
+
+ model_config = ConfigDict(from_attributes=True)
+
+
+class OrderCreate(BaseModel):
+ customer_id: int = Field(..., gt=0)
+ items: list[OrderItemCreate] = Field(
+ ..., min_length=1, description="Order must contain at least 1 item"
+ )
+
+
+class OrderOut(BaseModel):
+ id: int
+ customer_id: int
+ status: str
+ total_price: Decimal
+ created_at: datetime
+ items: list[OrderItemOut]
+
+ model_config = ConfigDict(from_attributes=True)