Skip to content

Commit

Permalink
Merge pull request #40 from yalla-coop/179-more-order-work
Browse files Browse the repository at this point in the history
179 more order work
  • Loading branch information
ajluker authored Jul 16, 2024
2 parents e4eb91f + 69d88e8 commit b3bb1cf
Show file tree
Hide file tree
Showing 21 changed files with 482 additions and 109 deletions.
2 changes: 1 addition & 1 deletion web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ app.use('/fdc', cors(), express.json(), legacyfdcRouter, errorMiddleware);

//todo: Who's enterprise is this? Is a hub posting to their own enterprise endpoint? Is it something that exists on the producer? Ask Garethe
app.use(
'/api/dfc/Enterprises/tbd/Orders',
'/api/dfc/Enterprises/:EnterpriseName/Orders',
cors(),
express.json(),
checkUserAccessPermissions,
Expand Down
1 change: 1 addition & 0 deletions web/database/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const buildProductTable = async () => {
await readSqlFile(process.cwd() + '/web/database/users/schema.sql');
await readSqlFile(process.cwd() + '/web/database/variants/schema.sql');
await readSqlFile(process.cwd() + '/web/database/line_items/schema.sql');
await readSqlFile(process.cwd() + '/web/database/orders/schema.sql');
await readSqlFile(process.cwd() + '/web/database/users/test-users.sql');
} catch (err) {
throw new Error(err);
Expand Down
33 changes: 21 additions & 12 deletions web/database/line_items/lineItems.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
import {pool} from '../connect.js'
export const createLineItems = async (orderId, lineItems) => {
import { pool } from '../connect.js'

export const createOrUpdateLineItems = async (orderId, lineItems) => {
const parameters = lineItems.map(line => ({ orderId, id: line.id, variantId: line.variantId }));
try {
const result = await pool.query(`
const result = await pool.query(`
INSERT INTO line_items (shopify_id, order_id, variant_id)
(SELECT *
FROM json_to_recordset($1)
AS x("id" bigint, "orderId" bigint, "variantId" bigint))
on CONFLICT(variant_id)
on CONFLICT(order_id, variant_id)
DO UPDATE SET
shopify_id = EXCLUDED.shopify_id
RETURNING *;
`,

[JSON.stringify(parameters)]
);
return result.rows;
} catch (err) {
throw new Error(err);
}
[JSON.stringify(parameters)]
);
return result.rows;
};

export const getLineItems = async (orderId) => {
return (await pool.query(`SELECT external_id as "externalId", shopify_id as "shopifyId", variant_id as "variantId" FROM line_items where order_id = $1`, [orderId])).rows;
};

export const getAllLineItems = async () => {
const lineItems = (await pool.query(`SELECT order_id as "draftOrderId", external_id as "externalId", shopify_id as "shopifyId", variant_id as "variantId" FROM line_items order by order_id`, [])).rows;
return lineItems.reduce((accumulator, lineItem) => {
const [lastOrder, ...others] = accumulator
if (lastOrder?.draftOrderId === lineItem.draftOrderId) {
return [{draftOrderId: lineItem.draftOrderId, lineItems: {[lineItem.shopifyId]: lineItem.externalId, ...lastOrder.lineItems}}, ...others];
} else {
return [{draftOrderId: lineItem.draftOrderId, lineItems: {[lineItem.shopifyId]: lineItem.externalId}}, ...accumulator]
}
}, []).reverse();
}

export const getLineItemIdMappings = async (orderId) => {
return (await getLineItems(orderId))
.reduce((mappings, mapping) => ({...mappings, [mapping.shopifyId]: mapping.externalId}), {})
.reduce((mappings, mapping) => ({ ...mappings, [mapping.shopifyId]: mapping.externalId }), {})
}
21 changes: 19 additions & 2 deletions web/database/line_items/lineItems.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {createLineItems, getLineItems} from './lineItems'
import {createOrUpdateLineItems, getLineItems, getLineItemIdMappings, getAllLineItems} from './lineItems'
import { pool } from '../connect';

describe('lineItems', () => {
Expand All @@ -7,11 +7,28 @@ describe('lineItems', () => {
});

it('Can be rembered and recalled', async () => {
await createLineItems(5, [{id: 1234, variantId: 55}, {id: 56678, variantId: 67}]);
await createOrUpdateLineItems(5, [{id: 1234, variantId: 55}, {id: 56678, variantId: 67}]);
const result = await getLineItems(5);
expect(result).toStrictEqual([{externalId: 1, shopifyId: "1234", variantId: "55"}, {externalId: 2, shopifyId: "56678", variantId: "67"}])
});

it('Can be updated', async () => {
await createOrUpdateLineItems(5, [{id: 1, variantId: 55}, {id: 2, variantId: 67}]);
await createOrUpdateLineItems(5, [{id: 3, variantId: 55}, {id: 4, variantId: 67}, {id: 5, variantId: 90}]);
const result = await getLineItemIdMappings(5);
expect(result).toStrictEqual( {"3": 1, "4": 2, "5": 5});
});

it('Can be loaded in bulk', async () => {
await createOrUpdateLineItems(1001, [{id: 9000, variantId: 55}, {id: 9001, variantId: 56}]);
await createOrUpdateLineItems(1002, [{id: 9003, variantId: 56}]);
const result = await getAllLineItems();
expect(result).toStrictEqual([
{draftOrderId: "1001", lineItems: {"9000": 1, "9001": 2}},
{draftOrderId: "1002", lineItems: {"9003": 3}}
])
});

it('returns empty array for no order', async () => {
expect(await getLineItems(1234)).toStrictEqual([]);
})
Expand Down
5 changes: 3 additions & 2 deletions web/database/line_items/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ DROP TABLE IF EXISTS "line_items" CASCADE;
CREATE TABLE IF NOT EXISTS "line_items" (
"external_id" SERIAL PRIMARY KEY,
"shopify_id" bigint NOT NULL,
"variant_id" bigint NOT NULL UNIQUE,
"variant_id" bigint NOT NULL,
"order_id" bigint NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT NOW(),
"updated_at" TIMESTAMP NOT NULL DEFAULT NOW()
"updated_at" TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT order_id_variant_id UNIQUE (order_id, variant_id)
);
CREATE TRIGGER set_timestamp BEFORE
UPDATE ON "line_items" FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
Expand Down
24 changes: 24 additions & 0 deletions web/database/orders/orders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { pool } from '../connect.js'

export const createDraftOrder = async (draftOrderId) => {
const result = await pool.query(`
INSERT INTO orders (draft_order_id)
VALUES ($1)
RETURNING *;
`, [draftOrderId]);
return result.rows;
};

export const completeDraftOrder = async (draftOrderId, completedOrderId) => {
const result = await pool.query(`
UPDATE orders set completed_order_id = $2
WHERE draft_order_id = $1
RETURNING *;
`, [draftOrderId, completedOrderId]);
return result.rows;
};

export const getOrders = async () => {
const result = await pool.query(`SELECT draft_order_id as "draftOrderId", completed_order_id as "completedOrderId" from orders order by draft_order_id`, []);
return result.rows;
}
21 changes: 21 additions & 0 deletions web/database/orders/orders.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { pool } from '../connect';
import {createDraftOrder, completeDraftOrder, getOrders} from './orders'

describe('orders', () => {
beforeAll(async () => {
await pool.query(`truncate table orders restart identity`);
});

it('Order can be created', async () => {
await createDraftOrder(55);
await createDraftOrder(56);
const result = await getOrders();
expect(result).toStrictEqual([{draftOrderId: "55", completedOrderId: null}, {draftOrderId: "56", completedOrderId: null}])
});

it('Order can be completed', async () => {
await completeDraftOrder(55, 654);
const result = await getOrders();
expect(result).toStrictEqual([{draftOrderId: "55", completedOrderId: "654"}, {draftOrderId: "56", completedOrderId: null}])
})
});
11 changes: 11 additions & 0 deletions web/database/orders/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
BEGIN;
DROP TABLE IF EXISTS "orders" CASCADE;
CREATE TABLE IF NOT EXISTS "orders" (
"draft_order_id" bigint PRIMARY KEY,
"completed_order_id" bigint NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT NOW(),
"updated_at" TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TRIGGER set_timestamp BEFORE
UPDATE ON "orders" FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import * as orders from './shopify/orders.js';

// transaction
const createOrUpdateOrderLine = async (req, res) => {
const session = await getSession(shopName)
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });

const orderLine = extractOrderLine(req.body)

const shopifyOrder = await orders.findOrder(client, req.params['id']);
const shopifyOrder = await orders.findOrder(client, req.params.id);

if (!shopifyOrder) {
return res.status(404).send('Unable to find order');
}

const updatedLines = await orders.createUpdatedShopifyLines(shopifyOrder, orderLine);
const updatedShopifyDraftOrder = await orders.updateOrder(client, req.params['id'], updatedLines);
const updatedShopifyDraftOrder = await orders.updateOrder(client, req.params.id, updatedLines);
const lineItemIdMappings = await persistLineIdMappings(updatedShopifyDraftOrder)
const dfcOrder = await createDfcOrderLineFromShopify(updatedShopifyDraftOrder, req.params['lineId'], lineItemIdMappings);
const dfcOrder = await createDfcOrderLineFromShopify(updatedShopifyDraftOrder, req.params.lineId, lineItemIdMappings, req.params.EnterpriseName, req.params.id);
res.type('application/json')
res.send(dfcOrder);
}
Expand Down
13 changes: 8 additions & 5 deletions web/fdc-modules/orders/controllers/create-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import getSession from '../../../utils/getShopifySession.js';
import { extractOrderAndLines, createDfcOrderFromShopify } from '../dfc/dfc-order.js';
import { findCustomer } from './shopify/customer.js';
import * as orders from './shopify/orders.js';
import {persistLineIdMappings} from './lineItemMappings.js'
import * as ids from './shopify/ids.js';
import { persistLineIdMappings } from './lineItemMappings.js'
import { createDraftOrder } from '../../../database/orders/orders.js'

const createOrder = async (req, res) => {
const session = await getSession(shopName)
const createOrder = async (req, res) => {
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });
const customerEmail = ''

const customerId = await findCustomer(client, customerEmail);
const order = extractOrderAndLines(req.body)
const shopifyLines = (await order.getLines()).map(orders.dfcLineToShopifyLine)
const shopifyDraftOrder = await orders.createShopifyOrder(client, customerId, customerEmail, shopifyLines);


await createDraftOrder(ids.extract(shopifyDraftOrder.id));
const lineItemIdMappings = await persistLineIdMappings(shopifyDraftOrder)
const dfcOrder = await createDfcOrderFromShopify(shopifyDraftOrder, lineItemIdMappings);
const dfcOrder = await createDfcOrderFromShopify(shopifyDraftOrder, lineItemIdMappings, req.params.EnterpriseName);
res.type('application/json')
res.send(dfcOrder);
}
Expand Down
21 changes: 21 additions & 0 deletions web/fdc-modules/orders/controllers/get-all-orders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getAllLineItems } from '../../../database/line_items/lineItems.js';
import shopify from '../../../shopify.js';
import getSession from '../../../utils/getShopifySession.js';
import { createBulkDfcOrderFromShopify } from '../dfc/dfc-order.js';
import { findOrders } from './shopify/orders.js';

const getAllOrders = async (req, res) => {
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });

const draftOrdersWithLineItemMappings = await getAllLineItems();

const shopifyOrders = await findOrders(client, draftOrdersWithLineItemMappings.map(({draftOrderId}) => draftOrderId));

const allDfcOrders = await createBulkDfcOrderFromShopify(shopifyOrders, draftOrdersWithLineItemMappings, req.params.EnterpriseName);

res.type('application/json')
res.send(allDfcOrders);
}

export default getAllOrders
6 changes: 3 additions & 3 deletions web/fdc-modules/orders/controllers/get-order-line.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { createDfcOrderLineFromShopify } from '../dfc/dfc-order.js';
import { findOrder } from './shopify/orders.js';

const getOrderLine = async (req, res) => {
const session = await getSession(shopName)
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });

const shopifyOrder = await findOrder(client, req.params['id']);
const shopifyOrder = await findOrder(client, req.params.id);

if (!shopifyOrder) {
return res.status(404).send('Unable to find order');
}

const dfcOrder = await createDfcOrderLineFromShopify(shopifyOrder, req.params['lineId'], await getLineItemIdMappings(shopifyOrder.id));
const dfcOrder = await createDfcOrderLineFromShopify(shopifyOrder, req.params.lineId, await getLineItemIdMappings(shopifyOrder.id), req.params.EnterpriseName, req.params.id);

if (!dfcOrder) {
res.status(404).send('Order ine not found');
Expand Down
6 changes: 3 additions & 3 deletions web/fdc-modules/orders/controllers/get-order-lines.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { createDfcOrderLinesFromShopify } from '../dfc/dfc-order.js';
import { findOrder } from './shopify/orders.js';

const getOrderLines = async (req, res) => {
const session = await getSession(shopName)
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });

const shopifyOrder = await findOrder(client, req.params['id']);
const shopifyOrder = await findOrder(client, req.params.id);

if (!shopifyOrder) {
return res.status(404).send('Unable to find order');
}

const dfcOrder = await createDfcOrderLinesFromShopify(shopifyOrder, await getLineItemIdMappings(shopifyOrder.id));
const dfcOrder = await createDfcOrderLinesFromShopify(shopifyOrder, await getLineItemIdMappings(shopifyOrder.id), req.params.EnterpriseName, req.params.id);
res.type('application/json')
res.send(dfcOrder);
}
Expand Down
7 changes: 4 additions & 3 deletions web/fdc-modules/orders/controllers/get-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import shopify from '../../../shopify.js';
import getSession from '../../../utils/getShopifySession.js';
import { createDfcOrderFromShopify } from '../dfc/dfc-order.js';
import { findOrder } from './shopify/orders.js';
import { getLineItemIdMappings } from '../../../database/line_items/lineItems.js'

const getOrder = async (req, res) => {
const session = await getSession(shopName)
const session = await getSession(`${req.params.EnterpriseName}.myshopify.com`)
const client = new shopify.api.clients.Graphql({ session });

const shopifyOrder = await findOrder(client, req.params['id']);
const shopifyOrder = await findOrder(client, req.params.id);

if (!shopifyOrder) {
return res.status(404).send('Unable to find order');
}

const dfcOrder = await createDfcOrderFromShopify(shopifyOrder, await getLineItemIdMappings(shopifyOrder.id));
const dfcOrder = await createDfcOrderFromShopify(shopifyOrder, await getLineItemIdMappings(shopifyOrder.id), req.params.EnterpriseName);
res.type('application/json')
res.send(dfcOrder);
}
Expand Down
15 changes: 9 additions & 6 deletions web/fdc-modules/orders/controllers/lineItemMappings.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {createLineItems, getLineItemIdMappings} from '../../../database/line_items/lineItems.js'
import {createOrUpdateLineItems, getLineItemIdMappings} from '../../../database/line_items/lineItems.js'
import * as ids from '../controllers/shopify/ids.js'

export async function persistLineIdMappings(shopifyDraftOrder) {

const draftOrderId = ids.extract(shopifyDraftOrder.id);

const mappings = shopifyDraftOrder.lineItems.edges.map(({node: lineItem}) => ({
id: lineItem.id,
variantId: lineItem.variant.id
id: ids.extract(lineItem.id),
variantId: ids.extract(lineItem.variant.id)
}));

await createLineItems(shopifyDraftOrder.id, mappings);
return await getLineItemIdMappings(shopifyDraftOrder.id);
}
await createOrUpdateLineItems(draftOrderId, mappings);
return await getLineItemIdMappings(draftOrderId);
}
11 changes: 11 additions & 0 deletions web/fdc-modules/orders/controllers/shopify/ids.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function extract(shopifyId) {
return shopifyId.substring(shopifyId.lastIndexOf('/') + 1);
}

export function variant(id) {
return `gid://shopify/ProductVariant/${id}`
}

export function draftOrder(id){
return `gid://shopify/DraftOrder/${id}`
}
Loading

0 comments on commit b3bb1cf

Please sign in to comment.