const { bigcommerceApiOAuth, serverBaseURL, bigcommerceStoreHash } = require("../config.js") let { clearSSRCache, createTibiCustomer, updateTibiCustomer } = require("../lib/utils") const { getProductImages, getOrderProductsById, getProductById, getCustomerById, getOrderById, createInternalOrderObject, } = require("../lib/bigcommerceRestAPI.js") const { createPrintfulWebhook, getPrintfulOrderShipments } = require("../lib/printfulRestAPI.js") const { postPurchase } = require("../lib/facebookRestAPI.js") ;(function () { const data = context.data if (context?.user?.auth()?.id) { if (context.data.type === "printful") { createPrintfulWebhook(context.data.scope) return } else { let url = `https://api.bigcommerce.com/stores/${bigcommerceStoreHash}/v3/hooks` let options = { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": bigcommerceApiOAuth }, body: JSON.stringify({ scope: context?.data?.scope, destination: `${serverBaseURL}webhook`, is_active: context?.data?.active, events_history_enabled: true, headers: { token: "super_secure_and_extremely_secret_big_commerce_webhook_token_123" }, }), } const response = context.http.fetch(url, options).body.json() const hookResponse = { data: context.data, } // @ts-ignore hookResponse.data.webhookId = response.data.id return hookResponse } } if (data) { if (data?.type === "order_updated") { const bigCommerceOrderId = data?.data?.order?.external_id const order = context.db.find("bigCommerceOrder", { filter: { bigCommerceId: Number(bigCommerceOrderId), }, })[0] if (order) { context.db.update("bigCommerceOrder", order.id, { status: data?.data?.order?.status, statusSetAt: new Date().toISOString(), }) } throw { status: 200, data: { message: "", }, } } else if (data?.type == "shipment_sent") { const bigCommerceOrderId = data?.data?.order?.external_id const printfulOrderShipments = getPrintfulOrderShipments(Number(bigCommerceOrderId)) const order = context.db.find("bigCommerceOrder", { filter: { bigCommerceId: Number(bigCommerceOrderId), }, })[0] if (order) { context.db.update("bigCommerceOrder", order.id, { shipments: (printfulOrderShipments || []).map((shipped) => { return { trackingUrl: shipped.tracking_url, trackingNumber: data?.data?.shipment?.tracking_number, carrier: shipped.carrier, sentAt: new Date(), } }), }) } throw { status: 200, data: { message: "", }, } } else if (data?.scope?.includes("product")) { if (data.scope.includes("product/deleted")) { handleProductDeleted(data.data.id) clearSSRCache() } else { const product = getProductById(data?.data?.id) const productImage = getProductImages(data?.data?.id) if (data.scope.includes("product/created") && product?.id) { handleProductCreateOrUpdate(product, productImage) } if (data.scope.includes("product/updated") && product?.id) { handleProductCreateOrUpdate(product, productImage) } clearSSRCache() } throw { status: 200, data: { message: "", }, } } else if (data?.scope?.includes("order")) { if (data.scope.includes("order/statusUpdated")) { if (data.data.status.new_status_id == 11) { const internalOrderReference = createInternalOrderObject(data.data.id) // make sure the order doesn't already exist const orderExists = context.db.find("bigCommerceOrder", { filter: { bigCommerceId: Number(data.data.id), }, }) if (!orderExists.length) context.db.create("bigCommerceOrder", internalOrderReference) else context.db.update("bigCommerceOrder", orderExists[0].id, internalOrderReference) /* not necessary for now, as bigcommerce itself takes care of it try { if (!orderExists) { postPurchase(internalOrderReference.cost.replace(",", ".")) } } catch (e) { console.log(e) }*/ } else { const order = context.db.find("bigCommerceOrder", { filter: { bigCommerceId: data.data.id, }, })[0] /** * * @param {any} orderStatus * @returns {PrintfulStates | false} */ function mapOrderStatusToPrintful(orderStatus) { switch (orderStatus.new_status_id) { case 0: case 1: case 7: case 11: return "draft" // Unvollständig case 6: return "failed" // Abgelehnt case 10: return "fulfilled" // Versandt, Versand ausstehend, Abgeschlossen case 3: return "partial" // Teilweise Versandt, Teilweise erstattet case 12: case 13: return "onhold" // Manuelle Überprüfung erforderlich, Umstritten (closest match) default: return false } } if (order && mapOrderStatusToPrintful(data.data.status) !== false) { context.db.update("bigCommerceOrder", order.id, { status: mapOrderStatusToPrintful(data.data.status), statusSetAt: new Date().toISOString(), }) } } } throw { status: 200, data: { message: "", }, } } else if (data?.scope?.includes("customer")) { let internalCustomer if (data.data?.id) /** @type {Customer} */ internalCustomer = context.db.find("bigCommerceCustomer", { filter: { bigCommerceId: data.data.id, }, })?.[0] || null if (data.scope.includes("customer/deleted") && !!internalCustomer) { context.db.delete("bigCommerceCustomer", internalCustomer.id) } else { const customer = getCustomerById(data?.data?.id) if (!internalCustomer && customer?.id) { createTibiCustomer(customer) } else if (data.scope.includes("customer/updated") && !!internalCustomer) { updateTibiCustomer(customer, internalCustomer) } } throw { status: 200, data: { message: "", }, } } else throw { status: 403, error: "Forbidden", } } else throw { status: 403, error: "Forbidden", } })() /** * Handles both product creation and update by checking if the product exists and then * creating or updating the record accordingly. * * @param {V2OrderProductsResponseBase} [product] The product data. * @param { ProductImage[]} [productImage] The product image data. */ function handleProductCreateOrUpdate(product, productImage) { const internalProduct = context.db.find("bigCommerceProduct", { filter: { bigCommerceId: Number(product?.id), }, })?.[0] || null if (internalProduct) { // If the product exists, update it. context.db.update("bigCommerceProduct", internalProduct.id || "", { productName: product?.name_customer || product?.name, bigCommerceSKU: product?.sku, previewImage: productImage?.[0]?.url_thumbnail, bigCommerceId: Number(product?.id), }) } else { // If the product does not exist, create it. context.db.create("bigCommerceProduct", { productName: product?.name_customer || product?.name, bigCommerceSKU: product?.sku, previewImage: productImage?.[0]?.url_thumbnail, bigCommerceId: Number(product?.id), }) } } /** * Handles product deletion by removing the product record if it exists. * @param { V2OrderProductsResponseBase } [id] The product data to delete. */ function handleProductDeleted(id) { const internalProduct = context.db.find("bigCommerceProduct", { filter: { bigCommerceId: Number(id), }, })[0] if (internalProduct) { context.db.delete("bigCommerceProduct", internalProduct.id || "") } }