← back to Dw Signup Fulfillment
scripts/activate-shopify.js
81 lines
'use strict';
// Idempotently activates the two Shopify resources owned by this app:
// the Function-backed automatic discount and the paid-order ledger webhook.
const config = require('../lib/config');
const shopify = require('../lib/shopify');
const TITLE = 'DW Free Samples (auto)';
const FUNCTION_ID = '01a0475d-d202-743e-bdc8-7a659f6ff512';
const CALLBACK = 'https://signup.designerwallcoverings.com/webhooks/orders-paid';
async function call(query, variables) {
const response = await shopify.graphql(query, variables);
if (!response.ok || response.json?.errors?.length) throw new Error(JSON.stringify(response.json?.errors || response.json));
return response.json.data;
}
async function main() {
if (!config.SHOPIFY_FULFILLMENT_TOKEN) throw new Error('SHOPIFY_FULFILLMENT_TOKEN is unset');
const existing = await call(`query Existing($search: String!) {
webhookSubscriptions(first: 50, topics: [ORDERS_PAID]) { nodes { id topic uri } }
discountNodes(first: 50, query: $search) {
nodes { id discount { __typename ... on DiscountAutomaticApp { title status startsAt combinesWith { productDiscounts orderDiscounts shippingDiscounts } appDiscountType { functionId } } } }
}
}`, { search: `title:${TITLE}` });
let webhook = existing.webhookSubscriptions.nodes.find(x => x.uri === CALLBACK);
let discount = existing.discountNodes.nodes.find(x => x.discount?.title === TITLE && x.discount?.appDiscountType?.functionId === FUNCTION_ID);
if (!process.argv.includes('--apply')) {
console.log(JSON.stringify({ apply: false, webhook: webhook || null, discount: discount || null }, null, 2));
return;
}
if (!webhook) {
const made = await call(`mutation CreateWebhook($input: WebhookSubscriptionInput!) {
webhookSubscriptionCreate(topic: ORDERS_PAID, webhookSubscription: $input) {
webhookSubscription { id topic uri }
userErrors { field message }
}
}`, { input: { callbackUrl: CALLBACK, format: 'JSON' } });
if (made.webhookSubscriptionCreate.userErrors.length) throw new Error(JSON.stringify(made.webhookSubscriptionCreate.userErrors));
webhook = made.webhookSubscriptionCreate.webhookSubscription;
}
if (!discount) {
const made = await call(`mutation CreateDiscount($input: DiscountAutomaticAppInput!) {
discountAutomaticAppCreate(automaticAppDiscount: $input) {
automaticAppDiscount { discountId title status startsAt appDiscountType { functionId } }
userErrors { field message code }
}
}`, { input: {
title: TITLE,
functionId: FUNCTION_ID,
discountClasses: ['PRODUCT'],
startsAt: new Date(Date.now() - 60_000).toISOString(),
combinesWith: { orderDiscounts: true, productDiscounts: true, shippingDiscounts: true },
} });
if (made.discountAutomaticAppCreate.userErrors.length) throw new Error(JSON.stringify(made.discountAutomaticAppCreate.userErrors));
discount = made.discountAutomaticAppCreate.automaticAppDiscount;
} else if (!discount.discount.combinesWith.productDiscounts) {
const made = await call(`mutation UpdateDiscount($id: ID!, $input: DiscountAutomaticAppInput!) {
discountAutomaticAppUpdate(id: $id, automaticAppDiscount: $input) {
automaticAppDiscount { discountId title status startsAt combinesWith { productDiscounts orderDiscounts shippingDiscounts } appDiscountType { functionId } }
userErrors { field message code }
}
}`, { id: discount.id, input: {
title: TITLE,
functionId: FUNCTION_ID,
discountClasses: ['PRODUCT'],
startsAt: discount.discount.startsAt,
combinesWith: { orderDiscounts: true, productDiscounts: true, shippingDiscounts: true },
} });
if (made.discountAutomaticAppUpdate.userErrors.length) throw new Error(JSON.stringify(made.discountAutomaticAppUpdate.userErrors));
discount = made.discountAutomaticAppUpdate.automaticAppDiscount;
}
console.log(JSON.stringify({ apply: true, webhook, discount }, null, 2));
}
main().catch(error => { console.error(error.message); process.exit(1); });