From e4e94b204033f04613d0c78cab966b48b9c61127 Mon Sep 17 00:00:00 2001 From: Sam Ban Date: Fri, 16 Sep 2022 23:11:43 +0100 Subject: [PATCH] apply discount (case b) --- package.json | 3 +- server.js | 98 +++++++++++++++++++++++++++++---- src/discount.js | 140 ++++++++++++++++++++++++++++++++++-------------- 3 files changed, 190 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index e22d5b6..364167e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "dependencies": { "dotenv": "^16.0.2", "node-fetch": "^3.2.10", - "redis": "^4.3.1" + "redis": "^4.3.1", + "request": "^2.88.2" }, "imports": { "@/*": "./src/*" diff --git a/server.js b/server.js index 2922a4d..7442d02 100644 --- a/server.js +++ b/server.js @@ -4,26 +4,52 @@ import { auth } from './src/auth.js'; import url from 'url'; import { createClient } from 'redis'; import { createWebhook, getVerification } from './src/sheerid.js'; +import { nano } from './src/nano.js'; +import { getCartDiscounts, createCartDiscount, createDiscountCode, applyDiscount, getCart, getCarts } from './src/discount.js'; +import fetch from 'node-fetch'; -const redis = createClient(); -redis.on('error', (err) => console.log('Redis Client Error', err)); +const token = await auth(); -console.log('connecting to Redis...'); -await redis.connect(); +const makeid = (length) => { + var result = ''; + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + var charactersLength = characters.length; + for (var i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return (result.substring(0, length / 2) + nano() + result.substring(length / 2, length)).toUpperCase(); +} const verificationStatus = async (verificationId) => { return await getVerification(verificationId); } const onSuccess = async (cartId, verificationData) => { - // create new discount code - // add directDiscount to cart return await redis.set(`cart-${cartId}`, JSON.stringify(verificationData)); } -import { getCartDiscounts, createCartDiscount, createDiscountCode } from './src/discount.js'; +const updateCart = async (sessionId, cartId) => { + const existing = await redis.get(`cartid-${sessionId}`); + if (existing) { + return; + } + const code = "ST"+makeid(6) + console.log('updating cart', cartId, code); + const cart = await getCart(token, cartId); + const res = await createDiscountCode(token, "Student Discount", config.CART_DISCOUNT_ID, code); + if (res) { + console.log(res); + const res2 = await applyDiscount(token, cartId, cart.version, code); + console.log(res2); + await redis.set(`cartid-${sessionId}`, cartId); + } +} -const token = await auth(); +const redis = createClient(); +redis.on('error', (err) => console.log('Redis Client Error', err)); + +console.log('connecting to Redis...'); +await redis.connect(); http.createServer(async (req, res) => { if (req.url === '/' && req.method === 'GET') { @@ -54,12 +80,65 @@ http.createServer(async (req, res) => { } res.writeHead(200, {'Content-Type': 'application/json'}); res.end(cartJson); + } else if (req.url.startsWith('/api/getcarts') && req.method === 'GET') { + const q = url.parse(req.url, true).query; + res.writeHead(200, {'Content-Type': 'application/json'}); + res.end(JSON.stringify(await getCarts(token))); } else if (req.url.startsWith('/api/update') && req.method === 'GET') { const q = url.parse(req.url, true).query; console.log('get /api/update', q.cid); - redis.set(`cartid-${q.cid}`, q.cart); res.writeHead(200, {'Content-Type': 'application/json'}); res.end(`{}`); + try { + updateCart(q.cid, q.cart); + } catch (e) { + console.log(e); + } + // return; + // const storedCart = await redis.get(`cart-${q.cid}`); + // if (!storedCart) { + // return; + // } + // const rb = await fetch("https://api.europe-west1.gcp.commercetools.com/sunrise-spa/graphql", { + // "headers": { + // "authorization": "Bearer "+q.t, + // "content-type": "application/json", + // }, + // "method": "POST", + // "body": "{\"operationName\":\"myCart\",\"variables\":{\"locale\":\"en\"},\"query\":\"query myCart($locale: Locale!) {\\n myCart: me {\\n activeCart {\\n cartId: id\\n version\\n lineItems {\\n lineId: id\\n name(locale: $locale)\\n productSlug(locale: $locale)\\n quantity\\n price {\\n value {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n discounted {\\n value {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n discount {\\n name(locale: $locale)\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n totalPrice {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n variant {\\n sku\\n images {\\n url\\n __typename\\n }\\n attributesRaw {\\n name\\n value\\n attributeDefinition {\\n type {\\n name\\n __typename\\n }\\n name\\n label(locale: $locale)\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n totalPrice {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n shippingInfo {\\n shippingMethod {\\n methodId: id\\n name\\n localizedDescription(locale: $locale)\\n __typename\\n }\\n price {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n __typename\\n }\\n taxedPrice {\\n totalGross {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n totalNet {\\n centAmount\\n currencyCode\\n fractionDigits\\n __typename\\n }\\n __typename\\n }\\n discountCodes {\\n discountCode {\\n codeId: id\\n code\\n name(locale: $locale)\\n __typename\\n }\\n __typename\\n }\\n shippingAddress {\\n firstName\\n lastName\\n streetName\\n additionalStreetInfo\\n postalCode\\n city\\n country\\n phone\\n email\\n __typename\\n }\\n billingAddress {\\n firstName\\n lastName\\n streetName\\n additionalStreetInfo\\n postalCode\\n city\\n country\\n phone\\n email\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\"}", + // }); + // const r = await rb.json(); + // const activeCart = await r.data.myCart.activeCart; + // console.log('cart version:', JSON.stringify(activeCart.version)); + + // const code = "ST"+makeid(6) + // console.log('updating cart', activeCart.cartId, code); + // const dc = await createDiscountCode(token, "Student Discount", config.CART_DISCOUNT_ID, code); + // console.log('discountcode:', dc); + // if (dc) { + // const qi = JSON.stringify({ + // "operationName":"mutateCart", + // "variables":{ + // "actions":[{"addDiscountCode":{"code": dc.code }}], + // "version":activeCart.version, + // "id":activeCart.cartId, + // }, + // "query":"mutation mutateCart($actions: [MyCartUpdateAction!]!, $version: Long!, $id: String!) {\n updateMyCart(actions: $actions, version: $version, id: $id) {\n id\n version\n lineItems {\nlineId: id\nquantity\n__typename\n}\n__typename\n}\n}", + // }) + // console.log('q', qi); + // fetch("https://api.europe-west1.gcp.commercetools.com/sunrise-spa/graphql", { + // "headers": { + // "authorization": "Bearer "+q.t, + // "content-type": "application/json", + // }, + // "method": "POST", + // "body": qi, + // }).then(async(res)=>{ + // const r = await res.json(); + // console.log(r) + // }); + // } + } else if (req.url === '/api/success-webhook' && req.method === 'POST') { console.log('post /api/success-webhook'); let body = []; @@ -76,7 +155,6 @@ http.createServer(async (req, res) => { const cartId = r.personInfo.metadata.cartid; console.log(`saving ${cartId} cart id`); onSuccess(cartId, r); - updateStatus(cartId, r); } else { console.log('no metadata', r); } diff --git a/src/discount.js b/src/discount.js index e2a70b1..c30e309 100644 --- a/src/discount.js +++ b/src/discount.js @@ -3,9 +3,31 @@ import { config } from './config.js'; const getCartDiscount = async (token, code) => { const res = await fetch(`${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/cart-discounts/${code}`, { - 'method': 'GET', - 'headers': { - 'Authorization': 'Bearer ' + token, + method: 'GET', + headers: { + Authorization: 'Bearer ' + token.access_token, + }, + }); + return await res.json(); +} + +const getCart = async (token, cartId) => { + console.log("getting",cartId, token.access_token); + const res = await fetch(`${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/carts/${cartId}`, { + method: 'GET', + headers: { + Authorization: 'Bearer ' + token.access_token, + }, + }); + return await res.json(); +} + +const getCarts = async (token) => { + console.log("getting ", token.access_token); + const res = await fetch(`${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/carts`, { + method: 'GET', + headers: { + Authorization: 'Bearer ' + token.access_token, }, }); return await res.json(); @@ -14,9 +36,9 @@ const getCartDiscount = async (token, code) => { const getCartDiscounts = async (token) => { const res = await fetch( `${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/cart-discounts`, { - 'method': 'GET', - 'headers': { - 'Authorization': 'Bearer ' + token, + method: 'GET', + headers: { + Authorization: 'Bearer ' + token.access_token, }, }); return await res.json(); @@ -26,54 +48,92 @@ const createCartDiscount = async (token, discount) => { const res = await fetch( `${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/cart-discounts`, { - 'method': 'POST', - 'headers': { + method: 'POST', + headers: { 'Authorization': 'Bearer ' + token.access_token, 'Content-Type': 'application/json' }, body: JSON.stringify({ - "name": { - "en": r.name, + name: { + en: r.name, }, - "value": { - "type": "relative", - "permyriad": 1000 + value: { + type: "relative", + permyriad: 1000 }, - "cartPredicate": "1=1", - "target": { - "type": "lineItems", - "predicate": "1=1" + cartPredicate: "1=1", + target: { + type: "lineItems", + predicate: "1=1" }, - "sortOrder": Math.random().toString(), - "isActive": true, - "requiresDiscountCode": false + sortOrder: Math.random().toString(), + isActive: true, + requiresDiscountCode: false }) }); + if (res.status != 200) { + console.log(res.status, res.body); + return false; + } return await res.json(); } -const createDiscountCode = (prefix, name, cartDiscountId) => { - fetch( +const createDiscountCode = async (token, name, cartDiscountId, cartDiscountCode) => { + const sjson = JSON.stringify({ + code: cartDiscountCode, + name: { en: name}, + cartDiscounts: [ + { + typeId: 'cart-discount', + id: cartDiscountId + } + ], + maxApplications: 1, + isActive: true, + cartPredicate: '1=1' + }) + const res = await fetch( `${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/discount-codes`, { - 'method': 'POST', - 'headers': { - 'Authorization': 'Bearer ' + token.access_token, + method: 'POST', + headers: { + Authorization: 'Bearer ' + token.access_token, 'Content-Type': 'application/json' }, - body: JSON.stringify({ - "code": prefix + makeid(6), - "name": name, - "cartDiscounts": [ - { - "typeId": "cart-discount", - "id": cartDiscountId - } - ], - "isActive": true, - "cartPredicate": "1=1" - }) - }) -} + body: sjson, + }); + // const rr = await res; + // if (res.status < 300) { + // console.log(sjson, res.status, await res.json()); + // return false; + // } + return await res.json(); +} + +const applyDiscount = async (token, cartId, version, discountCode) => { + console.log('applying discount to',cartId, version, discountCode); + const reqj = JSON.stringify({ + version: version, + actions: [{"action": "addDiscountCode", "code": discountCode}], + }); + const res = await fetch(`${config.CTP_API_URL}/${config.CTP_PROJECT_KEY}/carts/${cartId}`, + { + method: 'POST', + headers: { + Authorization: 'Bearer ' + token.access_token, + 'Content-Type': 'application/json' + }, + body: reqj, + }); + if (res.status > 299) { + try { + console.log(reqj, res, await res.json()); + } catch (e) { + console.log(e); + } + return false; + } + return await res.json(); +} -export { getCartDiscount, getCartDiscounts, createCartDiscount, createDiscountCode }; \ No newline at end of file +export { getCartDiscount, getCartDiscounts, createCartDiscount, createDiscountCode, applyDiscount, getCart, getCarts }; \ No newline at end of file