Skip to content

Shopping cart

Shopping cart example

-- Supported actions: add, remove, update
function main()
    -- example object
    local testConfig = {
        productId="---",
        offeringId="---",
        count=1,
        action="add"
    };
    mock("body", ToJson(testConfig))
    mock("userId", "---")
    local userId = param("userId")
    local body = FromJson(param("body"))

    local count = body.count or 1

    -- log the input parameters
    log.pairs(body)

    -- service id for identifying cart item for update
    local service = "cart:" .. userId .. ":" .. body.offeringId

    -- find the product, offering and cart item (if it exists)
    local product = first(core.QueryDispatch("id:"..body.productId, {"data", "body", "attachments"}))
    local offering = first(core.QueryDispatch("id:"..body.offeringId), {"data"})
    local existing = first(core.QueryDispatch("given service ["..service.."]", {"data"}))
    local result = {}

    local data = buildCart(product, offering, body.count, product.attachments)
    log.info("*******************")
    log.pairs(data)
    log.info("*******************")

    -- do something with the cart item
    if product == nil or offering == nil then
        -----------------------
        -- Error status
        log.error("Error: product and/or offering does not exist")

        result.success = false
        result.disposition = "error"
        result.message = "invalid product or offering"

    elseif body.action == "remove" then        
        -----------------------
        -- Remove
        result.disposition = "remove"
        result.success = true

        if existing ~= nil then
            core.RemoveUserBucketDispatch({ownerId=userId, dispatchId=existing.id, handle="shopping-cart"})
            core.DeleteDispatch(existing.id)

            buildCartTotal(userId, existing.id, {}, body.action)
        else
            buildCartTotal(userId, "nil", {}, body.action)
        end            

    else
        -----------------------
        -- Add or Update      
        log.info("Found product and offering")

        if existing ~= nil and existing.data ~= nil then
            log.info("Cart exists with count " .. existing.data.count)
            local existingCount = tonumber(existing.data.count or "0")

            -- add the current count if already there
            if body.action == "add" then                
                count = existingCount + count            
            end

        elseif cart ~= nil then
            log.info("Cart exists with invalid data")
            log.info (existing)
        end

        local image = first(product.attachments)
        local cart = buildCart(product, offering, count)                        

        -- update the disposition stuf
        result.count = count
        result.disposition = "add"

        local d = core.CreateOrUpdateDispatch({
            author=userId,
            userId=userId,
            trackerHandle="cart-item",
            attachments={image.id},
            data=cart,
            serviceId=service,
            when=Now()            
        })
        core.AddUserBucketDispatch({ownerId=userId, dispatchId=d, handle="shopping-cart"})  

        result.dispatch = d
        result.success = true

        buildCartTotal(userId, d, cart, body.action)
    end


    Result(result)
end

function buildCartTotal(userId, cartItem, itemDetails, action)

    local id = core.UserBucketLookup({ownerId=userId, handle="shopping-cart"})
    local ls = core.QueryDispatch("given bucket [" .. id .. "]")

    local count = 0
    local total = 0

    -- total up the cart
    for index, dispatch in pairs(ls) do         
        -- check to see if we should use local data (to avoid timing issues with saving the dispatch)
        -- don't add items that were removed
        subtotal = 0
        if dispatch.id == cartItem and action ~= "remove" then
            subtotal = tonumber(itemDetails.price) * itemDetails.count
            count = count +1                
        elseif dispatch.id ~= cartItem then
            subtotal = tonumber(dispatch.data.price) * tonumber(dispatch.data.count)
            count = count +1
        end

        total = total + subtotal
    end

    -- save the totals
    local service = "cartTotal:" .. userId
    local d = core.CreateOrUpdateDispatch({
            author=userId,
            userId=userId,
            trackerHandle="cart-total",
            data={count=count, total=total},
            serviceId=service,
            when=Now()            
        })
end


function buildCart(product, offering, count)
    -- ** From product, offering **
    -- product_name
    -- price
    -- unit
    -- nonStandardUnit
    -- size
    -- sku
    -- ** User **
    -- count    
    -- subtotal

    local subtotal = tonumber(offering.data.price) * count
    return {
        productName = product.data.product_name,
        price = offering.data.price,
        unit = offering.data.unit,
        nonStandardUnit = offering.data.nonStandardUnit,
        size = offering.data.size,
        sku = offering.data.sku,
        count = count,
        productId = product.id,
        offeringId = offering.id,
        subtotal = subtotal
    }
end


main()