102 lines
4.0 KiB
JavaScript
Executable File
102 lines
4.0 KiB
JavaScript
Executable File
// routes/configurePricing.js
|
|
const express = require('express');
|
|
const axios = require('axios');
|
|
const { v4: uuid } = require('uuid');
|
|
const { getToken } = require('../tokenStore');
|
|
const { log } = require('../logger');
|
|
|
|
const router = express.Router();
|
|
const processes = {};
|
|
|
|
// POST /configure-pricing
|
|
// body: { shop: string, priceType: "map" | "percentage", percentage: number }
|
|
router.post('/', async (req, res) => {
|
|
const { shop, priceType, percentage } = req.body;
|
|
if (!shop) return res.status(400).json({ error: 'Missing `shop`' });
|
|
|
|
const procId = uuid();
|
|
processes[procId] = { status: 'started', detail: null };
|
|
log(shop, `🔔 [${procId}] ConfigurePricing initiated (priceType=${priceType}, percentage=${percentage})`);
|
|
res.json({ processId: procId, status: 'started' });
|
|
|
|
(async () => {
|
|
try {
|
|
processes[procId].status = 'preparing';
|
|
|
|
// 1) Get token
|
|
const tokenRecord = getToken(shop);
|
|
if (!tokenRecord) throw new Error('No token for shop');
|
|
|
|
const adminUrl = `https://${shop}/admin/api/2025-10/graphql.json`;
|
|
const headers = {
|
|
'X-Shopify-Access-Token': tokenRecord.accessToken,
|
|
'Content-Type': 'application/json',
|
|
};
|
|
log(shop, `🔑 [${procId}] Using access token for shop ${shop}`);
|
|
|
|
// 2) Fetch Shop GID
|
|
processes[procId].status = 'fetching_shop';
|
|
const shopIdQuery = `{ shop { id name } }`;
|
|
const shopIdResp = await axios.post(adminUrl, { query: shopIdQuery }, { headers });
|
|
const shopId = shopIdResp.data?.data?.shop?.id;
|
|
if (!shopId) throw new Error(`Could not fetch shop id: ${JSON.stringify(shopIdResp.data)}`);
|
|
log(shop, `🏷️ [${procId}] Shop GID: ${shopId}`);
|
|
|
|
// 3) Sanitize + build config JSON
|
|
const normalizedType = (priceType || 'map').toString().toLowerCase();
|
|
const validType = ['map', 'percentage'].includes(normalizedType) ? normalizedType : 'map';
|
|
const rawPct = Number(percentage);
|
|
const validPct = Number.isFinite(rawPct) ? rawPct : 0;
|
|
|
|
const cfg = { priceType: validType, percentage: validPct };
|
|
const cfgValue = JSON.stringify(cfg);
|
|
|
|
log(shop, `🧾 [${procId}] Saving pricing_config: ${cfg.priceType}/${cfg.percentage}%`);
|
|
|
|
// 4) Save metafield (inline GraphQL, double-stringify value to embed JSON safely)
|
|
processes[procId].status = 'saving_metafield';
|
|
const resp = await axios.post(adminUrl, {
|
|
query: `
|
|
mutation {
|
|
metafieldsSet(metafields: [{
|
|
namespace: "turn14",
|
|
key: "pricing_config",
|
|
type: "json",
|
|
ownerId: "${shopId}",
|
|
value: ${JSON.stringify(cfgValue)}
|
|
}]) {
|
|
metafields { id key }
|
|
userErrors { field message }
|
|
}
|
|
}
|
|
`
|
|
}, { headers });
|
|
|
|
const errs = resp.data?.data?.metafieldsSet?.userErrors || [];
|
|
if (errs.length) {
|
|
log(shop, `⚠️ [${procId}] metafieldsSet errors: ${JSON.stringify(errs)}`);
|
|
processes[procId].status = 'error';
|
|
processes[procId].detail = JSON.stringify(errs);
|
|
return;
|
|
}
|
|
|
|
log(shop, `✅ [${procId}] pricing_config metafield saved`);
|
|
processes[procId].status = 'done';
|
|
processes[procId].detail = null;
|
|
} catch (err) {
|
|
processes[procId].status = 'error';
|
|
processes[procId].detail = err.message;
|
|
log(shop, `❌ [${procId}] Error: ${err.message}`);
|
|
}
|
|
})();
|
|
});
|
|
|
|
// Optional: check status (same shape as manageBrands)
|
|
router.get('/status/:processId', (req, res) => {
|
|
const info = processes[req.params.processId];
|
|
if (!info) return res.status(404).json({ error: 'Not found' });
|
|
res.json(info);
|
|
});
|
|
|
|
module.exports = router;
|