99 lines
3.8 KiB
JavaScript
Executable File
99 lines
3.8 KiB
JavaScript
Executable File
const axios = require('axios');
|
|
const { log } = require('./logger');
|
|
|
|
/**
|
|
* Create (or retrieve existing) fulfillment service + location for a shop.
|
|
* Returns { fulfillmentService, locationId } — locationId is NEVER null if a
|
|
* fulfillment service exists, because we fall back to the service's own location.
|
|
*/
|
|
async function createFulfillmentService(shop, accessToken) {
|
|
const client = axios.create({
|
|
baseURL: `https://${shop}/admin/api/2025-10/graphql.json`,
|
|
headers: {
|
|
'X-Shopify-Access-Token': accessToken,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
try {
|
|
log(shop, `🚀 [FulfillmentService] Creating fulfillment service...`);
|
|
|
|
// ── Step 1: Create fulfillment service (or retrieve existing) ────────────
|
|
const createResp = await client.post('', {
|
|
query: `
|
|
mutation {
|
|
fulfillmentServiceCreate(
|
|
name: "Data4Autos Distribution",
|
|
callbackUrl: "https://backend.data4autos.com/fulfillment"
|
|
) {
|
|
fulfillmentService {
|
|
id serviceName callbackUrl handle
|
|
location { id name }
|
|
}
|
|
userErrors { field message }
|
|
}
|
|
}
|
|
`,
|
|
});
|
|
|
|
let fulfillmentService = createResp.data?.data?.fulfillmentServiceCreate?.fulfillmentService;
|
|
const createErrors = createResp.data?.data?.fulfillmentServiceCreate?.userErrors || [];
|
|
|
|
if (createErrors.length > 0) {
|
|
log(shop, `⚠️ [FulfillmentService] Create errors: ${JSON.stringify(createErrors)}`);
|
|
// Service likely already exists — query it instead
|
|
log(shop, `🔍 [FulfillmentService] Querying existing fulfillment service...`);
|
|
const existingResp = await client.post('', {
|
|
query: `
|
|
query {
|
|
fulfillmentServices(type: THIRD_PARTY) {
|
|
id serviceName callbackUrl handle
|
|
location { id name }
|
|
}
|
|
}
|
|
`,
|
|
});
|
|
const services = existingResp.data?.data?.fulfillmentServices || [];
|
|
fulfillmentService = services.find(s => s.handle === 'data4autos-distribution') || services[0] || null;
|
|
|
|
if (!fulfillmentService) {
|
|
log(shop, `❌ [FulfillmentService] Could not create or find existing service`);
|
|
return { fulfillmentService: null, locationId: null };
|
|
}
|
|
log(shop, `✅ [FulfillmentService] Found existing: ${fulfillmentService.id}`);
|
|
} else {
|
|
log(shop, `✅ [FulfillmentService] Created: ${fulfillmentService.id}`);
|
|
}
|
|
|
|
// ── Step 2: Get the shop's primary location ID ───────────────────────────
|
|
// Shopify never returns a location from fulfillmentServiceCreate — use the
|
|
// shop's first active location (the physical/online store location) instead.
|
|
let locationId = null;
|
|
try {
|
|
const locResp = await client.post('', {
|
|
query: `query { locations(first: 1, includeLegacy: true) { nodes { id name isActive } } }`,
|
|
});
|
|
const locNode = locResp.data?.data?.locations?.nodes?.[0];
|
|
if (locNode?.id) {
|
|
locationId = locNode.id;
|
|
log(shop, `📍 [FulfillmentService] Primary shop location: "${locNode.name}" → ${locationId}`);
|
|
} else {
|
|
log(shop, `⚠️ [FulfillmentService] No locations returned from Shopify`);
|
|
}
|
|
} catch (locErr) {
|
|
log(shop, `⚠️ [FulfillmentService] Could not fetch shop location: ${locErr.message}`);
|
|
}
|
|
|
|
log(shop, `📍 [FulfillmentService] Final locationId: ${locationId}`);
|
|
|
|
return { fulfillmentService, locationId };
|
|
|
|
} catch (error) {
|
|
const errDetail = error.response ? JSON.stringify(error.response.data) : error.message;
|
|
log(shop, `💥 [FulfillmentService] Request failed: ${errDetail}`);
|
|
return { fulfillmentService: null, locationId: null };
|
|
}
|
|
}
|
|
|
|
module.exports = { createFulfillmentService };
|