const pg = require('../pg') const joinjs = require('join-js').default; const debug = require('debug')('sos:db:order') const mappings = require('../mappings') const dbUtil = require('../util') const {DateTime} = require('luxon') const easypost = new (require('@easypost/api'))(process.env.EASYPOST_API_KEY); const order = module.exports = {} order.create = async function(cart_uuid){ const query = { text: 'select * from sos.create_order($1)', values: [cart_uuid] } debug(query); const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'orderMap', 'order_')[0]; } order.findForCart = async function(cart_uuid) { const query = { text: 'select * from sos.find_order_for_cart($1)', values: [cart_uuid] } debug(query) const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'orderMap', 'order_')[0]; } order.addAddress = async function (transaction, address){ // Get parcel size const parcel = { weight: .2 * transaction.cart.items.length, width: 10, length: transaction.cart.items.length, height: 3 } // Create shipment const epShipment = new easypost.Shipment({ to_address: address.easypost_id, from_address: { street1: '11381 N. Sampson Drive', city: 'Highland', state: 'UT', zip: '84003', country: 'US' }, parcel }) await epShipment.save() // Get shipping price (as cents) const lowestRate = epShipment.lowestRate(['USPS']) const price = parseFloat(lowestRate && lowestRate.retail_rate) * 100 if(!price) throw new Error("Unable to estimate price"); // TODO: Update with real tax rate const tax = epShipment.to_address.state === 'UT' ? 200 : null // Update database const query = { text: 'select * from sos.add_address_to_order($1, $2, $3, $4)', values: [transaction.uuid, address.uuid, price, tax] } debug(query) const {rows} = await pg.query(query) return joinjs.map(rows, mappings, 'orderMap', 'order_')[0]; } order.addCoupon = function(transaction, coupon) { // Check coupon validity const couponExpireTime = DateTime.fromJSDate(coupon.valid_until) if(couponExpireTime.diffNow().as('seconds') < 0) throw new Error("Coupon has expired"); const {item_total_price} = transaction let discount = 0; if(coupon.flat_discount_cents) discount = coupon.flat_discount_cents; if(coupon.percent_discount) discount = Math.ceil(item_total_price * coupon.percent_discount / 100) if(coupon.per_sock_discount_cents) discount = transaction.cart.items // For each item type, create an array of length n (number of items of that type in cart) // where each index is initialized to the item price .map(({item, count}) => new Array(count).fill(item.price_cents)) // Flatten to just be all prices .flat() // For each price, convert it to the per-item discount (max of item price) .map(price => Math.min(price, coupon.per_sock_discount_cents)) // Sum all the discounts .reduce((a,c) => (a+c)) if(coupon.number_of_socks_free) discount = transaction.cart.items // For each item type, create an array of length n (number of items of that type in cart) // where each index is initialized to the item price .map(({item, count}) => new Array(count).fill(item.price_cents)) // Flatten to just be all prices .flat() // Order so the most expensive are at the front .sort((a,b) => (b-a)) // Keep only first n items .slice(0, coupon.number_of_socks_free) // Sum the item costs for total discount .reduce((a,c) => (a+c)) return dbUtil.executeFunction({ name: 'add_coupon_to_transaction', params: [ transaction.uuid, coupon.uuid, discount ], returnType: 'order', single: true }) }