diff --git a/CargoHubV2/app/controllers/packinglist_controller.py b/CargoHubV2/app/controllers/packinglist_controller.py new file mode 100644 index 0000000..9d1eef9 --- /dev/null +++ b/CargoHubV2/app/controllers/packinglist_controller.py @@ -0,0 +1,33 @@ +from fastapi import APIRouter, HTTPException, Depends, Header +from sqlalchemy.orm import Session +from CargoHubV2.app.database import get_db +from CargoHubV2.app.services import packinglist_service +from CargoHubV2.app.models.orders_model import Order +from fastapi.responses import FileResponse +from pathlib import Path + +router = APIRouter( + prefix="/api/v2/packinglist", + tags=["packinglist"] +) + +@router.get("/api/v2/packinglist/{order_id}") +def create_packing_list( + order_id: int, + db: Session = Depends(get_db), + api_key: str = Header(...), +): + order = db.query(Order).filter(Order.id == order_id).first() + if not order: + raise HTTPException(status_code=404, detail="Order not found") + return packinglist_service.generate_packing_list(order) + + +@router.get("/get-pdf/{filename}") +def get_pdf(filename: str): + PDF_DIR = Path("generated_pdfs") + pdf_path = PDF_DIR/filename + if pdf_path.exists(): + return FileResponse(pdf_path, media_type="application/pdf", filename=filename) + else: + raise HTTPException(status_code=404, detail="PDF not found") \ No newline at end of file diff --git a/CargoHubV2/app/main.py b/CargoHubV2/app/main.py index 2991519..18601a7 100644 --- a/CargoHubV2/app/main.py +++ b/CargoHubV2/app/main.py @@ -13,6 +13,7 @@ from CargoHubV2.app.controllers import inventories_controller from CargoHubV2.app.controllers import orders_controller from CargoHubV2.app.controllers import reporting_controller +from CargoHubV2.app.controllers import packinglist_controller from CargoHubV2.app.controllers import docks_controller import time from starlette.responses import JSONResponse @@ -38,6 +39,7 @@ app.include_router(shipments_controller.router) app.include_router(inventories_controller.router) app.include_router(orders_controller.router) +app.include_router(packinglist_controller.router) app.include_router(docks_controller.router) logger = logging.getLogger("uvicorn.error") diff --git a/CargoHubV2/app/packinglist_template.html b/CargoHubV2/app/packinglist_template.html new file mode 100644 index 0000000..614eef0 --- /dev/null +++ b/CargoHubV2/app/packinglist_template.html @@ -0,0 +1,61 @@ + + + + + + + Packing List + + + + +

Packing List

+

Warehouse ID: {{ warehouse_id }}

+

Source ID: {{ source_id }}

+

Order ID: {{ order_id }}

+

Order Date: {{ order_date }}

+

Request Date: {{ request_date }}

+

Shipping Notes: {{ shipping_notes }}

+

Total Different Items: {{ total_items }}

+

Total Amount of Items: {{ total_amount }}

+ +

Items

+ + + + + + + + + {% for item in items %} + + + + + {% endfor %} + +
Item IDQuantity
{{ item.item_id }}{{ item.amount }}
+ + + \ No newline at end of file diff --git a/CargoHubV2/app/services/packinglist_service.py b/CargoHubV2/app/services/packinglist_service.py new file mode 100644 index 0000000..9fdf40f --- /dev/null +++ b/CargoHubV2/app/services/packinglist_service.py @@ -0,0 +1,72 @@ +import io +import os +import json +import pdfkit +import base64 +import matplotlib.pyplot as plt + +from pathlib import Path +from jinja2 import Template +from itertools import chain +from datetime import datetime +from sqlalchemy import extract +from sqlalchemy.orm import Session +from fastapi import HTTPException, status, FastAPI +from CargoHubV2.app.models.orders_model import Order +from fastapi.responses import FileResponse, JSONResponse + + +PDF_DIR = Path("generated_pdfs") +PDF_DIR.mkdir(exist_ok=True) + +TEMPLATE_FILE = Path(os.path.dirname(__file__)).parent / "packinglist_template.html" + + +def generate_packing_list(order: Order): + try: + # Parse the items data from the order + try: + items = json.loads(order.items) if isinstance(order.items, str) else order.items + if not isinstance(items, list): + raise ValueError("Items should be a list of dictionaries with 'item_id' and 'amount'.") + except json.JSONDecodeError: + raise ValueError("Failed to decode order items. Ensure items are in valid JSON format.") + + + total_amount = sum(item["amount"] for item in items) + + # Prepare data for the packing list + content = { + "warehouse_id": order.warehouse_id, + "source_id": order.source_id, + "shipping_notes": order.shipping_notes, + "order_date": order.order_date.strftime("%Y-%m-%d"), + "order_id": order.id, + "request_date": order.request_date.strftime("%Y-%m-%d"), + "total_items": len(items), + "total_amount": total_amount, + "items": [{"item_id": item["item_id"], "amount": item["amount"]} for item in items], # Simplified item list + } + + # Load the packing list template + with open(TEMPLATE_FILE, "r") as file: + html_template = file.read() + + # Render the template + template = Template(html_template) + html_content = template.render(**content) + + # Define PDF file path + pdf_filename = f"packinglist_order_{order.id}.pdf" + pdf_path = PDF_DIR / pdf_filename + + # Generate PDF + pdfkit.from_string(html_content, str(pdf_path)) + + # Return the file URL or file path + pdf_url = f"http://127.0.0.1:3000/api/v2/packinglist/get-pdf/{pdf_filename}" + return JSONResponse({"message": "Packing list PDF generated successfully.", "pdf_url": pdf_url}) + except ValueError as ve: + raise HTTPException(status_code=400, detail=str(ve)) + except Exception as e: + raise HTTPException(status_code=500, detail=f"Error generating packing list PDF, {e}") diff --git a/generated_pdfs/packinglist_order_1.pdf b/generated_pdfs/packinglist_order_1.pdf new file mode 100644 index 0000000..9e876bf Binary files /dev/null and b/generated_pdfs/packinglist_order_1.pdf differ