|
|
|
const router = module.exports = require('express-promise-router')()
|
|
|
|
const parseJSON = require('body-parser').json()
|
|
|
|
const db = require('../db')
|
|
|
|
const stripe = require('stripe')(process.env.STRIPE_PRIVATE_KEY);
|
|
|
|
const easypost = new (require('@easypost/api'))(process.env.EASYPOST_API_KEY);
|
|
|
|
const ensureAdmin = require('./middleware/ensureAdmin')
|
|
|
|
const ensureCart = require('./middleware/ensureCart')
|
|
|
|
|
|
|
|
const validate = require('./middleware/validators')
|
|
|
|
|
|
|
|
router.get('/', async (req, res) => {
|
|
|
|
if(req.user)
|
|
|
|
// TODO: Write this function
|
|
|
|
return res.json(await db.order.findAllforUser(req.user.uuid))
|
|
|
|
else
|
|
|
|
return res.json(await db.order.findAllForSession(req.session.uuid))
|
|
|
|
})
|
|
|
|
|
|
|
|
router.get('/all', ensureAdmin, async (req, res) => {
|
|
|
|
const orders = await db.order.findAllComplete()
|
|
|
|
res.json(orders)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.put('/', ensureCart, async (req, res) => {
|
|
|
|
const order = await db.order.create(req.cart.uuid, req.sessionObj.uuid);
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.get('/current', ensureCart, async (req, res) => {
|
|
|
|
const order = await db.order.findForCart(req.cart.uuid);
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.get('/:uuid', ensureAdmin, async (req, res) => {
|
|
|
|
const order = await db.order.findByUUID(req.params.uuid)
|
|
|
|
|
|
|
|
if(order && order.delivery && order.delivery.easypost_id)
|
|
|
|
order.delivery.easypost = await easypost.Shipment.retrieve(order.delivery.easypost_id)
|
|
|
|
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/current/address', ensureCart, parseJSON, validate.address, validate.handleApiError, async (req, res) => {
|
|
|
|
const origOrder = await db.order.findForCart(req.cart.uuid);
|
|
|
|
if(!origOrder) throw new Error("Unable to find current order");
|
|
|
|
|
|
|
|
const currentTransaction = origOrder
|
|
|
|
.transactions.find(transaction => (
|
|
|
|
transaction.payment_state === 'started'
|
|
|
|
))
|
|
|
|
|
|
|
|
const {name, street1, street2, city, state, zip, country} = req.body;
|
|
|
|
|
|
|
|
// Create address, update order
|
|
|
|
const address = await db.address.create(name, street1, street2, city, state, zip, country)
|
|
|
|
const order = await db.order.addAddress(currentTransaction, address)
|
|
|
|
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/current/coupon', ensureCart, parseJSON, validate.coupon, validate.handleApiError, async (req, res) => {
|
|
|
|
const origOrder = await db.order.findForCart(req.cart.uuid);
|
|
|
|
if(!origOrder) throw new Error("Unable to find current order");
|
|
|
|
|
|
|
|
const coupon = await db.coupon.find(req.body.code)
|
|
|
|
|
|
|
|
const currentTransaction = origOrder
|
|
|
|
.transactions.find(transaction => (
|
|
|
|
transaction.payment_state === 'started'
|
|
|
|
))
|
|
|
|
|
|
|
|
const order = await db.order.addCoupon(currentTransaction, coupon)
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/current/checkout/stripe', ensureCart, async (req, res) => {
|
|
|
|
const order = await db.order.findForCart(req.cart.uuid);
|
|
|
|
if(!order) throw new Error("Unable to find current order");
|
|
|
|
|
|
|
|
const currentTransaction = order
|
|
|
|
.transactions.find(transaction => (
|
|
|
|
transaction.payment_state === 'started'
|
|
|
|
))
|
|
|
|
|
|
|
|
const {item_total_price, shipping_price, tax_price, coupon_effective_discount} = currentTransaction
|
|
|
|
const {free_shipping} = currentTransaction.coupon || {}
|
|
|
|
|
|
|
|
const numberOfItems = currentTransaction.cart.items.map(i => i.count).reduce((a,b) => a+b)
|
|
|
|
const itemPriceWithDiscount = item_total_price - (coupon_effective_discount || 0)
|
|
|
|
const shippingPrice = (free_shipping ? 0 : shipping_price)
|
|
|
|
|
|
|
|
const line_items = []
|
|
|
|
|
|
|
|
if(itemPriceWithDiscount > 0)
|
|
|
|
line_items.push({
|
|
|
|
name: `Cart Total (${numberOfItems} item${numberOfItems > 1 ? 's' : ''})`,
|
|
|
|
amount: itemPriceWithDiscount,
|
|
|
|
currency: 'usd',
|
|
|
|
quantity: 1
|
|
|
|
})
|
|
|
|
|
|
|
|
if(shippingPrice > 0)
|
|
|
|
line_items.push({
|
|
|
|
name: 'Shipping',
|
|
|
|
amount: shippingPrice,
|
|
|
|
currency: 'usd',
|
|
|
|
quantity: 1
|
|
|
|
})
|
|
|
|
|
|
|
|
if(tax_price > 0)
|
|
|
|
line_items.push({
|
|
|
|
name: 'Sales Tax (Utah)',
|
|
|
|
amount: tax_price,
|
|
|
|
currency: 'usd',
|
|
|
|
quantity: 1
|
|
|
|
})
|
|
|
|
|
|
|
|
// TODO: We need to handle this case, mark it paid or something?
|
|
|
|
if(line_items.length < 1)
|
|
|
|
res.json(null)
|
|
|
|
|
|
|
|
const session = await stripe.checkout.sessions.create({
|
|
|
|
client_reference_id: currentTransaction.uuid,
|
|
|
|
customer_email: req.user ? req.user.email : undefined,
|
|
|
|
payment_method_types: ['card'],
|
|
|
|
line_items,
|
|
|
|
success_url: `${process.env.EXTERNAL_URL}/store/checkout/verify?session_id={CHECKOUT_SESSION_ID}`,
|
|
|
|
cancel_url: `${process.env.EXTERNAL_URL}/cancel`,
|
|
|
|
});
|
|
|
|
|
|
|
|
res.json(session.id)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/current/checkout/verify', ensureCart, parseJSON, async (req, res) => {
|
|
|
|
const {session_id} = req.body
|
|
|
|
if(!session_id) throw new Error("No session id given")
|
|
|
|
|
|
|
|
let order = await db.order.findForCart(req.cart.uuid);
|
|
|
|
if(!order) throw new Error("Unable to find current order");
|
|
|
|
|
|
|
|
const currentTransaction = order
|
|
|
|
.transactions.find(transaction => (
|
|
|
|
transaction.payment_state === 'started'
|
|
|
|
))
|
|
|
|
|
|
|
|
const {payment_intent} = await stripe.checkout.sessions.retrieve(session_id);
|
|
|
|
const payment = await stripe.paymentIntents.retrieve(payment_intent)
|
|
|
|
|
|
|
|
// Handle this better?
|
|
|
|
if(payment.status !== "succeeded")
|
|
|
|
return res.json({status: payment.status})
|
|
|
|
|
|
|
|
try {
|
|
|
|
order = await db.order.addPayment(currentTransaction, payment)
|
|
|
|
|
|
|
|
await db.session.clearCart(req.sessionObj.uuid)
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err)
|
|
|
|
throw new Error("Unable to complete order")
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res.json({status: payment.status, order})
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/:uuid/ship/tracking', ensureAdmin, parseJSON, async (req, res) => {
|
|
|
|
const order = await db.order.setTracking(req.params.uuid, req.body.code, req.body.date || null)
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/:uuid/ship/delivery', ensureAdmin, parseJSON, async (req, res) => {
|
|
|
|
const order = await db.order.setDelivery(req.params.uuid, req.body.description, req.body.date || null)
|
|
|
|
res.json(order)
|
|
|
|
})
|
|
|
|
|
|
|
|
router.post('/:uuid/ship/easypost', ensureAdmin, parseJSON, async (req, res) => {
|
|
|
|
const order = await db.order.shipEasyPost(
|
|
|
|
req.params.uuid,
|
|
|
|
req.body.length,
|
|
|
|
req.body.width,
|
|
|
|
req.body.height,
|
|
|
|
req.body.weight
|
|
|
|
)
|
|
|
|
|
|
|
|
res.json(order)
|
|
|
|
})
|