Shorten printful/webflow naming convention
This commit is contained in:
@@ -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
@@ -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,
|
||||
})),
|
||||
});
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user