Recipes · 2 of 6

E-commerce — orders, carts, refunds

Schema

products: {sku, name, price, stock, sold}
carts:    {_id, user_id, items:[{sku, qty}], total, status}
orders:   {_id, user_id, items, total, status}
accounts: {user_id, balance}

add_to_cart

proc add_to_cart(user_id, sku, qty) {
    let p = find_one("products", {sku: sku})
    if p == null          { abort "product not found" }
    if p.stock < qty      { abort "out of stock" }

    let cart = find_one("carts", {user_id: user_id, status: "open"})
    if cart == null {
        insert("carts", {
            user_id: user_id, status: "open", total: p.price * qty,
            items: [{sku: sku, qty: qty, price: p.price}]
        })
    } else {
        update("carts", {_id: cart._id}, {
            $push: {items: {sku: sku, qty: qty, price: p.price}},
            $inc: {total: p.price * qty}
        })
    }
    return {ok: true}
}

checkout

proc checkout(user_id) {
    let cart = find_one("carts", {user_id: user_id, status: "open"})
    if cart == null      { abort "no open cart" }
    if cart.total <= 0   { abort "empty cart" }

    let acc = find_one("accounts", {user_id: user_id})
    if acc.balance < cart.total { abort "insufficient funds" }

    // Reserve stock
    for item in cart.items {
        update("products", {sku: item.sku}, {$inc: {stock: -item.qty, sold: item.qty}})
    }

    // Charge buyer
    update("accounts", {user_id: user_id}, {$inc: {balance: -cart.total}})

    // Convert cart to order
    let order_id = insert("orders", {
        user_id: user_id, items: cart.items, total: cart.total, status: "confirmed"
    })
    update("carts", {_id: cart._id}, {$set: {status: "converted", order_id: order_id}})

    return {ok: true, order_id: order_id, charged: cart.total}
}

refund

proc refund(order_id, reason, actor) {
    let order = find_one("orders", {_id: order_id})
    if order == null            { abort "order not found" }
    if order.status == "refunded" { abort "already refunded" }

    // Refund money
    update("accounts", {user_id: order.user_id}, {$inc: {balance: order.total}})

    // Restock
    for item in order.items {
        update("products", {sku: item.sku}, {$inc: {stock: item.qty, sold: -item.qty}})
    }

    update("orders", {_id: order_id}, {$set: {status: "refunded", refund_reason: reason}})
    insert("audit_log", {action: "refund", target: order_id, actor: actor, amount: order.total})
    return {ok: true, refunded: order.total}
}

cancel_cart

proc cancel_cart(user_id) {
    let cart = find_one("carts", {user_id: user_id, status: "open"})
    if cart == null { return {ok: true, was_empty: true} }
    update("carts", {_id: cart._id}, {$set: {status: "cancelled"}})
    return {ok: true}
}

top_products

proc top_products(n) {
    return aggregate("products", [
        {$match: {sold: {$gt: 0}}},
        {$sort: {sold: -1}},
        {$limit: n},
        {$project: {sku: 1, name: 1, sold: 1}}
    ])
}
Report Issue