swadhinbiswas fix: remove highlight.js CSS import causing Docker build failure · 7/20/2026
299a084
144 lines · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""shop.cart — shopping cart lifecycle and checkout (cart -> order + payment)."""
from __future__ import annotations

from justapi import HTTPException

from .config import app, db
from .db import q, q1, new_token
from .schemas import CartItemIn, CheckoutIn, validate


@app.post("/carts", status_code=201)
def create_cart(request):
    body = request.json() or {}
    customer_id = body.get("customer_id")
    if customer_id:
        if not q1("SELECT id FROM customers WHERE id = ?", [customer_id]):
            raise HTTPException(status_code=404, detail="customer not found")
    cart_id = new_token("cart")
    db().execute("INSERT INTO carts (id, customer_id) VALUES (?,?)", [cart_id, customer_id])
    return _cart_view(cart_id)


@app.get("/carts/{cart_id}")
def get_cart(request, cart_id: str):
    return _cart_view(cart_id)


@app.post("/carts/{cart_id}/items", body_schema=CartItemIn)
def add_cart_item(request, cart_id: str):
    d = validate(CartItemIn, request.json())
    if not q1("SELECT id FROM carts WHERE id = ?", [cart_id]):
        raise HTTPException(status_code=404, detail="cart not found")
    prod = q1("SELECT id, stock, active FROM products WHERE id = ?", [d.product_id])
    if not prod:
        raise HTTPException(status_code=404, detail="product not found")
    if not prod["active"]:
        raise HTTPException(status_code=409, detail="product not available")
    if d.quantity <= 0:
        raise HTTPException(status_code=422, detail="quantity must be > 0")
    if d.quantity > prod["stock"]:
        raise HTTPException(status_code=409, detail=f"only {prod['stock']} in stock")
    db().execute(
        "INSERT INTO cart_items (cart_id, product_id, quantity) VALUES (?,?,?) "
        "ON CONFLICT(cart_id, product_id) DO UPDATE SET quantity=excluded.quantity",
        [cart_id, d.product_id, d.quantity],
    )
    db().execute("UPDATE carts SET updated_at = datetime('now') WHERE id = ?", [cart_id])
    return _cart_view(cart_id)


@app.delete("/carts/{cart_id}/items/{product_id}", status_code=204)
def remove_cart_item(request, cart_id: str, product_id: str):
    res = db().execute(
        "DELETE FROM cart_items WHERE cart_id = ? AND product_id = ?",
        [cart_id, product_id],
    )
    if int(res) == 0:
        raise HTTPException(status_code=404, detail="item not in cart")
    return None


def _cart_view(cart_id: str) -> dict:
    cart = q1("SELECT * FROM carts WHERE id = ?", [cart_id])
    if not cart:
        raise HTTPException(status_code=404, detail="cart not found")
    items = q(
        "SELECT ci.product_id, p.name_pt, p.price, ci.quantity, "
        "(p.price * ci.quantity) AS line_total "
        "FROM cart_items ci JOIN products p ON p.id = ci.product_id "
        "WHERE ci.cart_id = ? ORDER BY ci.product_id",
        [cart_id],
    )
    total = sum((it["line_total"] or 0) for it in items)
    return {
        "id": cart["id"],
        "customer_id": cart["customer_id"],
        "updated_at": cart["updated_at"],
        "items": items,
        "item_count": len(items),
        "total": round(total, 2),
    }


@app.post("/carts/{cart_id}/checkout", body_schema=CheckoutIn)
def checkout(request, cart_id: str):
    d = validate(CheckoutIn, request.json())
    cart = q1("SELECT * FROM carts WHERE id = ?", [cart_id])
    if not cart:
        raise HTTPException(status_code=404, detail="cart not found")
    items = q(
        "SELECT ci.product_id, p.name_pt, p.price, p.stock, ci.quantity "
        "FROM cart_items ci JOIN products p ON p.id = ci.product_id "
        "WHERE ci.cart_id = ?",
        [cart_id],
    )
    if not items:
        raise HTTPException(status_code=422, detail="cart is empty")
    # Validate stock for every line before touching anything.
    for it in items:
        if it["quantity"] > it["stock"]:
            raise HTTPException(
                status_code=409,
                detail=f"product {it['product_id']} only has {it['stock']} in stock",
            )

    customer_id = cart["customer_id"]
    if not customer_id:
        raise HTTPException(status_code=422, detail="cart has no customer_id; set one first")

    order_id = new_token("order")
    total = round(sum((it["price"] * it["quantity"]) for it in items), 2)

    # One atomic transaction: create order, items, payment, decrement stock.
    stmts = [
        ("INSERT INTO orders (id, customer_id, status, total_amount) VALUES (?,?,?,?)",
         [order_id, customer_id, "paid", total]),
        ("INSERT INTO payments (order_id, method, installments, amount) VALUES (?,?,?,?)",
         [order_id, d.method, d.installments, total]),
    ]
    for it in items:
        stmts.append((
            "INSERT INTO order_items (order_id, product_id, quantity, unit_price, freight) "
            "VALUES (?,?,?,?,?)",
            [order_id, it["product_id"], it["quantity"], it["price"], 0.0],
        ))
        stmts.append((
            "UPDATE products SET stock = stock - ? WHERE id = ?",
            [it["quantity"], it["product_id"]],
        ))
    stmts.append(("UPDATE orders SET paid_at = datetime('now') WHERE id = ?", [order_id]))
    # Empty the cart after a successful purchase.
    stmts.append(("DELETE FROM cart_items WHERE cart_id = ?", [cart_id]))

    try:
        db().transaction(stmts)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"checkout failed: {e}")

    return q1(
        "SELECT id, customer_id, status AS order_status, total_amount, created_at, paid_at "
        "FROM orders WHERE id = ?",
        [order_id],
    )