Shorten printful/webflow naming convention

This commit is contained in:
Dominic Ferrando
2026-07-04 15:28:59 -04:00
parent afdc8de77c
commit a7b8dd0bea
7 changed files with 231 additions and 231 deletions
@@ -7,8 +7,8 @@ export async function up(db: Kysely<any>): Promise<void> {
.$call(addDefaultColumns)
.addColumn("session_id", "uuid", (cb) => cb.notNull())
.addColumn("session_name", "text", (cb) => cb.notNull())
.addColumn("printful_product_id_filter", sql`integer[]`)
.addColumn("syncing_printful_product_ids", sql`integer[]`, (cb) => cb
.addColumn("p_product_id_filter", sql`integer[]`)
.addColumn("syncing_p_product_ids", sql`integer[]`, (cb) => cb
.notNull()
.defaultTo(sql`'{}'::integer[]`)
)
+37 -37
View File
@@ -155,31 +155,31 @@ export const app = new Elysia()
return {
startDate: latestSync.started_at,
status: s.Commerce.Sync.deriveStatus(latestSync),
syncingPrintfulProductIds: latestSync.syncing_printful_product_ids
syncingPProductIds: latestSync.syncing_p_product_ids
}
})
// Run sync
.post("/:printfulProductId?", async ({ params: { printfulProductId }, sessionId }) => {
.post("/:pProductId?", async ({ params: { pProductId }, sessionId }) => {
await s.Commerce.Sync.start({
session: { id: sessionId, name: "Portal" },
filter: {
printfulProductIds: printfulProductId ? [printfulProductId] : null
pProductIds: pProductId ? [pProductId] : null
}
});
}, { params: t.Object({ printfulProductId: t.Optional(t.Numeric()) }) }),
}, { params: t.Object({ pProductId: t.Optional(t.Numeric()) }) }),
)
.get("/:printfulProductId", async ({ params: { printfulProductId } }) => {
const printfulProduct = await s.Commerce.Printful.Products.get(printfulProductId);
if (!printfulProduct) throw new NotFoundError("Missing printful product");
.get("/:pProductId", async ({ params: { pProductId } }) => {
const pProduct = await s.Commerce.Printful.Products.get(pProductId);
if (!pProduct) throw new NotFoundError("Missing printful product");
const webflowProductId = printfulProduct.sync_product.external_id.split("-")[0];
if (!webflowProductId) throw new NotFoundError("Missing webflow product ID");
const wProductId = pProduct.sync_product.external_id.split("-")[0];
if (!wProductId) throw new NotFoundError("Missing webflow product ID");
const webflowProduct = await s.Commerce.Webflow.Products.get(webflowProductId);
const wProduct = await s.Commerce.Webflow.Products.get(wProductId);
return { printfulProduct, webflowProduct };
return { pProduct, wProduct };
}, {
params: t.Object({ printfulProductId: t.Numeric() })
params: t.Object({ pProductId: t.Numeric() })
})
)
@@ -190,37 +190,37 @@ export const app = new Elysia()
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const printfulProduct = payload.data.sync_product;
log.info({ productId: printfulProduct.id }, "printful webhook: product updated");
const pProduct = payload.data.sync_product;
log.info({ productId: pProduct.id }, "printful webhook: product updated");
await s.Commerce.Sync.start({
session: { id: randomUUIDv7(), name: "Printful" },
filter: {
printfulProductIds: [printfulProduct.id]
pProductIds: [pProduct.id]
}
});
break;
}
case Printful.Webhook.Event.ProductDeleted: {
const printfulProduct = payload.data.sync_product;
const webflowProductId = printfulProduct.external_id.split("-")[0];
log.info({ externalId: payload.data.sync_product.external_id, webflowProductId }, "printful webhook: product deleted");
if (!webflowProductId) throw new NotFoundError("Missing webflow product ID");
const pProduct = payload.data.sync_product;
const wProductId = pProduct.external_id.split("-")[0];
log.info({ externalId: payload.data.sync_product.external_id, wProductId }, "printful webhook: product deleted");
if (!wProductId) throw new NotFoundError("Missing webflow product ID");
await s.Commerce.Webflow.Products.remove(webflowProductId);
await s.Commerce.Webflow.Products.remove(wProductId);
break;
}
case Printful.Webhook.Event.PackageShipped: {
const webflowOrderId = payload.data.order.external_id;
const wOrderId = payload.data.order.external_id;
const shipInfo = payload.data.shipment;
log.info({ webflowOrderId, carrier: shipInfo.carrier, tracking: shipInfo.tracking_number }, "printful webhook: package shipped");
log.info({ wOrderId, carrier: shipInfo.carrier, tracking: shipInfo.tracking_number }, "printful webhook: package shipped");
await s.Commerce.Webflow.Orders.update(webflowOrderId, {
await s.Commerce.Webflow.Orders.update(wOrderId, {
shippingTrackingURL: shipInfo.tracking_url,
shippingTracking: shipInfo.tracking_number,
shippingProvider: shipInfo.carrier,
});
await s.Commerce.Webflow.Orders.fulfill(webflowOrderId, {
await s.Commerce.Webflow.Orders.fulfill(wOrderId, {
sendOrderFulfilledEmail: true,
});
break;
@@ -237,27 +237,27 @@ export const app = new Elysia()
switch (payload.triggerType) {
case Webflow.Webhook.Event.OrderCreated: {
const webflowOrder = payload.payload;
log.info({ orderId: webflowOrder.orderId }, "webflow webhook: order created");
const wOrder = payload.payload;
log.info({ orderId: wOrder.orderId }, "webflow webhook: order created");
await s.Commerce.Printful.Orders.create({
external_id: webflowOrder.orderId,
external_id: wOrder.orderId,
// TODO: derive from webflow
shipping: "STANDARD",
recipient: {
name: webflowOrder.shippingAddress.addressee,
address1: webflowOrder.shippingAddress.line1,
address2: webflowOrder.shippingAddress.line2,
city: webflowOrder.shippingAddress.city,
name: wOrder.shippingAddress.addressee,
address1: wOrder.shippingAddress.line1,
address2: wOrder.shippingAddress.line2,
city: wOrder.shippingAddress.city,
state_code: zipcodesUs.find(
webflowOrder.shippingAddress.postalCode.split("-")[0] ?? "",
wOrder.shippingAddress.postalCode.split("-")[0] ?? "",
).stateCode,
country_code: webflowOrder.shippingAddress.country,
zip: webflowOrder.shippingAddress.postalCode,
country_code: wOrder.shippingAddress.country,
zip: wOrder.shippingAddress.postalCode,
},
items: webflowOrder.purchasedItems.map((webflowOrderSku) => ({
external_variant_id: webflowOrderSku.variantId,
quantity: webflowOrderSku.count,
items: wOrder.purchasedItems.map((wOrderSku) => ({
external_variant_id: wOrderSku.variantId,
quantity: wOrderSku.count,
})),
});
+8 -8
View File
@@ -52,7 +52,7 @@ class SyncService {
session_id: queuedSync.session.id,
session_name: queuedSync.session.name,
started_at: startDate,
printful_product_id_filter: queuedSync.filter?.printfulProductIds ?? null,
p_product_id_filter: queuedSync.filter?.pProductIds ?? null,
};
if (id) {
const result = await db.updateTable("product_syncs")
@@ -73,17 +73,17 @@ class SyncService {
id = result.id;
}
},
onStep: async (printfulProductIds: number[]) => {
onStep: async (pProductIds: number[]) => {
if (!id) throw new Error("Expected sync run ID");
await db.updateTable("product_syncs")
.set({ syncing_printful_product_ids: printfulProductIds })
.set({ syncing_p_product_ids: pProductIds })
.where("id", "=", id)
.execute();
},
onCompletion: async (completionDate, duration) => {
if (!id) throw new Error("Expected sync run ID");
await db.updateTable("product_syncs")
.set({ syncing_printful_product_ids: [], ended_at: completionDate })
.set({ syncing_p_product_ids: [], ended_at: completionDate })
.where("id", "=", id)
.execute();
freedSlot = true;
@@ -104,7 +104,7 @@ class SyncService {
if (Date.now() - (activeSync.started_at?.getTime() ?? 0) > 600000) {
log.info("already active sync exceeded timeout");
await db.updateTable("product_syncs")
.set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true })
.set({ syncing_p_product_ids: [], ended_at: new Date(), has_failed: true })
.where("id", "=", activeSync.id)
.execute();
await this.start(queuedSync);
@@ -117,7 +117,7 @@ class SyncService {
else {
if (id) {
await db.updateTable("product_syncs")
.set({ syncing_printful_product_ids: [], ended_at: new Date(), has_failed: true })
.set({ syncing_p_product_ids: [], ended_at: new Date(), has_failed: true })
.where("id", "=", id)
.execute();
freedSlot = true;
@@ -173,7 +173,7 @@ class SyncQueueService {
const values: Insertable<ProductSyncs> = {
session_id: queuedSync.session.id,
session_name: queuedSync.session.name,
printful_product_id_filter: queuedSync.filter?.printfulProductIds ?? null
p_product_id_filter: queuedSync.filter?.pProductIds ?? null
};
if (queuedSync.id) {
await db.updateTable("product_syncs")
@@ -204,7 +204,7 @@ class SyncQueueService {
name: result.session_name
},
filter: {
printfulProductIds: result.printful_product_id_filter
pProductIds: result.p_product_id_filter
}
}
}
@@ -9,7 +9,7 @@
const synchronizer = $state({
status: "none" as SyncStatus,
syncingPrintfulProductIds: [] as number[],
syncingPProductIds: [] as number[],
get isInProgress() {
return this.status === "active" || this.status === "queued";
},
@@ -17,11 +17,11 @@
const res = await api.products.sync.get();
if (res.error) {
synchronizer.status = "none";
synchronizer.syncingPrintfulProductIds = [];
synchronizer.syncingPProductIds = [];
} else {
synchronizer.status = res.data.status;
synchronizer.syncingPrintfulProductIds =
res.data.syncingPrintfulProductIds;
synchronizer.syncingPProductIds =
res.data.syncingPProductIds;
}
},
startPolling: () => {
@@ -34,9 +34,9 @@
synchronizer.startPolling();
await api.products.sync.post();
},
sync: async (printfulProductId: number) => {
sync: async (pProductId: number) => {
synchronizer.startPolling();
await api.products.sync({ printfulProductId }).post();
await api.products.sync({ pProductId }).post();
},
});
@@ -48,18 +48,18 @@
});
const isProductSynced = async (
printfulProduct: Printful.Products.SyncProduct,
pProduct: Printful.Products.SyncProduct,
) => {
const webflowProducts = await data.products.webflow;
return webflowProducts.some(
(p) => p.product.id === printfulProduct.external_id.split("-")[0],
const wProducts = await data.products.webflow;
return wProducts.some(
(p) => p.product.id === pProduct.external_id.split("-")[0],
);
};
</script>
{#await data.products.printful}
<p>Loading...</p>
{:then printfulProducts}
{:then pProducts}
<button
disabled={synchronizer.isInProgress}
onclick={() => synchronizer.syncAll()}
@@ -81,27 +81,27 @@
</tr>
</thead>
<tbody>
{#each printfulProducts as printfulProduct}
{#each pProducts as pProduct}
<tr class="hover:bg-base-300">
<td
><button
onclick={async () => {
const res = await api
.products({
printfulProductId:
printfulProduct.id,
pProductId:
pProduct.id,
})
.get();
console.log(res.data);
}}
class="cursor-pointer underline"
>
{printfulProduct.name}
{pProduct.name}
</button></td
>
<td>
{#await isProductSynced(printfulProduct) then isSynced}
{#if synchronizer.syncingPrintfulProductIds.includes(printfulProduct.id)}
{#await isProductSynced(pProduct) then isSynced}
{#if synchronizer.syncingPProductIds.includes(pProduct.id)}
<div class="badge badge-warning">
Syncing...
</div>
@@ -120,7 +120,7 @@
<button
disabled={synchronizer.status === "active"}
onclick={() =>
synchronizer.sync(printfulProduct.id)}
synchronizer.sync(pProduct.id)}
class="btn"
>
Sync