Implement product updating logic

This commit is contained in:
Dominic Ferrando
2025-06-06 14:52:25 -04:00
parent f93f9a7529
commit e6ca83192f
2 changed files with 110 additions and 10 deletions
+7 -2
View File
@@ -15,18 +15,21 @@ const server = Bun.serve({
async POST(req) { async POST(req) {
const payload: Printful.Webhook.EventPayload = await req.json() const payload: Printful.Webhook.EventPayload = await req.json()
console.log(JSON.stringify(payload)); console.log(JSON.stringify(payload));
console.log("PRINTFUL WEBHOOK: " + payload.type);
switch (payload.type) { switch (payload.type) {
// ADD/UPDATE
case Printful.Webhook.Event.ProductUpdated: case Printful.Webhook.Event.ProductUpdated:
const printfulProduct = await Printful.getSyncProduct(payload.data.sync_product.id) const printfulProduct = await Printful.getSyncProduct(payload.data.sync_product.id)
const productRecord = productRecords.findFromPrintful(payload.data.sync_product.id) const productRecord = productRecords.findFromPrintful(payload.data.sync_product.id)
if (productRecord) { if (productRecord) {
await Webflow.createProduct(printfulProduct, productRecords); await Webflow.updateProduct(printfulProduct, productRecords);
} }
else { else {
await Webflow.createProduct(printfulProduct, productRecords);
} }
break; break;
// DELETE
case Printful.Webhook.Event.ProductDeleted: case Printful.Webhook.Event.ProductDeleted:
break; break;
} }
@@ -38,4 +41,6 @@ const server = Bun.serve({
development: true development: true
}) })
productRecords.add({ webflowProductId: 123, printfulProductId: 321 });
console.log(`Listening on ${server.url}`); console.log(`Listening on ${server.url}`);
+103 -8
View File
@@ -43,6 +43,108 @@ export namespace Webflow {
} }
} }
export async function updateProduct(printfulProduct: Printful.Products.SyncProduct, productRecords: ProductRecords) {
const webflowProductId = productRecords.findFromPrintful(printfulProduct.result.sync_product.id)?.webflowProductId;
if (!webflowProductId) {
throw new Error("Product is not recognized");
}
const printfulVariants = printfulProduct.result.sync_variants;
const webflowVariants: Products.Sku[] = [];
for (const printfulVariant of printfulVariants) {
webflowVariants.push({
"fieldData": {
"name": printfulVariant.name,
"slug": formatSlug(printfulVariant.name),
"sku-values": {
"color": printfulVariant.color,
"size": printfulVariant.size,
},
"price": {
"value": +printfulVariant.retail_price * 100,
"unit": printfulVariant.currency,
"currency": printfulVariant.currency
},
// TODO: sync image
"main-image": "https://www.example.com/image.jpg"
}
});
}
const variantColors = printfulVariants.map(v => v.color);
const variantSizes = printfulVariants.map(v => v.size);
const variantExternalIds = printfulVariants.map(v => v.external_id);
const foundColors = Array.from(new Set(variantColors));
const foundSizes = Array.from(new Set(variantSizes));
let updateProductResponse = await fetch(`${API_URL}/products/${webflowProductId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}`,
},
body: JSON.stringify({
"product": {
"fieldData": {
"name": printfulProduct.result.sync_product.name,
"slug": formatSlug(printfulProduct.result.sync_product.name),
"sku-properties": [
{
"id": "color",
"name": "Color",
"enum": foundColors.map(color => ({
"id": color,
"slug": formatSlug(color),
"name": color
}))
},
{
"id": "size",
"name": "Size",
"enum": foundSizes.map(size => ({
"id": size,
"slug": formatSlug(size),
"name": size
}))
},
]
}
},
"sku": webflowVariants[0]
})
});
updateProductResponse = await updateProductResponse.json();
const getProductResponse = await fetch(`${API_URL}/products/${webflowProductId}`, {
method: "GET",
headers: {
"Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}`
}
});
const product = await getProductResponse.json();
for (let i = 0; i < product["skus"].length; ++i) {
const webflowSkuId = variantExternalIds[i];
await fetch(`${API_URL}/products/${webflowProductId}/skus/${webflowSkuId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": `bearer ${Bun.env.WEBFLOW_AUTH}`
},
body: JSON.stringify({
"sku": webflowVariants[i]
})
});
}
return {
"updateProduct": updateProductResponse,
};
}
export async function createProduct(printfulProduct: Printful.Products.SyncProduct, productRecords: ProductRecords) { export async function createProduct(printfulProduct: Printful.Products.SyncProduct, productRecords: ProductRecords) {
const printfulVariants = printfulProduct.result.sync_variants; const printfulVariants = printfulProduct.result.sync_variants;
@@ -61,7 +163,7 @@ export namespace Webflow {
"unit": printfulVariant.currency, "unit": printfulVariant.currency,
"currency": printfulVariant.currency "currency": printfulVariant.currency
}, },
// TODO // TODO: sync image
"main-image": "https://www.example.com/image.jpg" "main-image": "https://www.example.com/image.jpg"
} }
}); });
@@ -71,7 +173,6 @@ export namespace Webflow {
const foundSizes = Array.from(new Set(printfulVariants.map(v => v.size))); const foundSizes = Array.from(new Set(printfulVariants.map(v => v.size)));
// CREATE WEBFLOW PRODUCT // CREATE WEBFLOW PRODUCT
console.log("CREATE WEBFLOW PRODUCT");
let addProductResponse = await fetch(`${API_URL}/products`, { let addProductResponse = await fetch(`${API_URL}/products`, {
method: "POST", method: "POST",
headers: { headers: {
@@ -109,13 +210,11 @@ export namespace Webflow {
}) })
}); });
addProductResponse = await addProductResponse.json(); addProductResponse = await addProductResponse.json();
console.log(JSON.stringify(addProductResponse));
const webflowProductId = addProductResponse["product"]["id"]; const webflowProductId = addProductResponse["product"]["id"];
const printfulProductId = printfulProduct.result.sync_product.id; const printfulProductId = printfulProduct.result.sync_product.id;
// CREATE WEBFLOW PRODUCT SKUs // CREATE WEBFLOW PRODUCT SKUs
console.log("CREATE SKUS");
let createSkuResponse = await fetch(`${API_URL}/products/${webflowProductId}/skus`, { let createSkuResponse = await fetch(`${API_URL}/products/${webflowProductId}/skus`, {
method: "POST", method: "POST",
headers: { headers: {
@@ -127,12 +226,10 @@ export namespace Webflow {
}) })
}); });
createSkuResponse = await createSkuResponse.json(); createSkuResponse = await createSkuResponse.json();
console.log(JSON.stringify(createSkuResponse));
const responseSkus = [addProductResponse["sku"], ...createSkuResponse["skus"]]; const responseSkus = [addProductResponse["sku"], ...createSkuResponse["skus"]];
// SYNC WEBFLOW/PRINTFUL PRODUCT AND VARIANT IDs // SYNC WEBFLOW/PRINTFUL PRODUCT AND VARIANT IDs
console.log("SYNC PRODUCT IDs");
let modifyPrintfulProductResponse = await fetch(`${Printful.API_URL}/store/products/${printfulProductId}`, { let modifyPrintfulProductResponse = await fetch(`${Printful.API_URL}/store/products/${printfulProductId}`, {
method: "PUT", method: "PUT",
headers: { headers: {
@@ -151,10 +248,8 @@ export namespace Webflow {
}) })
}); });
modifyPrintfulProductResponse = await modifyPrintfulProductResponse.json(); modifyPrintfulProductResponse = await modifyPrintfulProductResponse.json();
console.log(JSON.stringify(modifyPrintfulProductResponse));
// CACHE WEBFLOW/PRINTFUL PRODUCT ASSOCIATION // CACHE WEBFLOW/PRINTFUL PRODUCT ASSOCIATION
console.log("CACHING PRODUCT ASSOCIATION");
productRecords.add({ printfulProductId, webflowProductId }); productRecords.add({ printfulProductId, webflowProductId });
} }
} }