From 750bb03628716116e3110014ef9647aaeef7550d Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Sat, 16 Dec 2023 12:40:17 +0100 Subject: [PATCH 1/4] fix: migrate segment subscribers + typescript support --- packages/medusa-plugin-segment/.babelrc | 13 - packages/medusa-plugin-segment/package.json | 23 +- .../src/subscribers/claim-created.ts | 46 +++ .../src/subscribers/order-canceled.ts | 31 ++ .../src/subscribers/order-items-returned.ts | 91 +++++ .../src/subscribers/order-placed.ts | 96 +++++ .../src/subscribers/order-shipment-created.ts | 69 ++++ .../src/subscribers/order.js | 338 ------------------ .../src/subscribers/swap-created.ts | 24 ++ .../src/subscribers/swap-payment-completed.ts | 36 ++ .../src/subscribers/swap-shipment-created.ts | 41 +++ .../src/subscribers/swap.js | 149 -------- .../src/utils/gather-swap-report.ts | 71 ++++ .../medusa-plugin-segment/tsconfig.admin.json | 8 + packages/medusa-plugin-segment/tsconfig.json | 35 ++ .../tsconfig.server.json | 7 + .../medusa-plugin-segment/tsconfig.spec.json | 5 + yarn.lock | 15 +- 18 files changed, 570 insertions(+), 528 deletions(-) delete mode 100644 packages/medusa-plugin-segment/.babelrc create mode 100644 packages/medusa-plugin-segment/src/subscribers/claim-created.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/order-canceled.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/order-placed.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts delete mode 100644 packages/medusa-plugin-segment/src/subscribers/order.js create mode 100644 packages/medusa-plugin-segment/src/subscribers/swap-created.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/swap-payment-completed.ts create mode 100644 packages/medusa-plugin-segment/src/subscribers/swap-shipment-created.ts delete mode 100644 packages/medusa-plugin-segment/src/subscribers/swap.js create mode 100644 packages/medusa-plugin-segment/src/utils/gather-swap-report.ts create mode 100644 packages/medusa-plugin-segment/tsconfig.admin.json create mode 100644 packages/medusa-plugin-segment/tsconfig.json create mode 100644 packages/medusa-plugin-segment/tsconfig.server.json create mode 100644 packages/medusa-plugin-segment/tsconfig.spec.json diff --git a/packages/medusa-plugin-segment/.babelrc b/packages/medusa-plugin-segment/.babelrc deleted file mode 100644 index 4d2dfe8f09274..0000000000000 --- a/packages/medusa-plugin-segment/.babelrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "plugins": [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-transform-instanceof", - "@babel/plugin-transform-classes" - ], - "presets": ["@babel/preset-env"], - "env": { - "test": { - "plugins": ["@babel/plugin-transform-runtime"] - } - } -} diff --git a/packages/medusa-plugin-segment/package.json b/packages/medusa-plugin-segment/package.json index 4598e08d101d0..81a08fc987eda 100644 --- a/packages/medusa-plugin-segment/package.json +++ b/packages/medusa-plugin-segment/package.json @@ -14,36 +14,27 @@ "author": "Sebastian Rindom", "license": "MIT", "devDependencies": { - "@babel/cli": "^7.7.5", - "@babel/core": "^7.7.5", - "@babel/node": "^7.7.4", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-transform-classes": "^7.9.5", - "@babel/plugin-transform-instanceof": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.7.6", - "@babel/preset-env": "^7.7.5", - "@babel/register": "^7.7.4", - "@babel/runtime": "^7.9.6", "cross-env": "^5.2.1", "eslint": "^6.8.0", "jest": "^25.5.4", "medusa-interfaces": "^1.3.7", - "medusa-test-utils": "^1.1.40" + "medusa-test-utils": "^1.1.40", + "rimraf": "^5.0.1", + "typescript": "^4.9.5" }, "scripts": { - "prepare": "cross-env NODE_ENV=production yarn run build", + "prepublishOnly": "cross-env NODE_ENV=production tsc --build", "test": "jest --passWithNoTests src", - "build": "babel src --out-dir . --ignore '**/__tests__','**/__mocks__'", - "watch": "babel -w src --out-dir . --ignore '**/__tests__','**/__mocks__'" + "build": "rimraf dist && tsc -p ./tsconfig.server.json && medusa-admin bundle", + "watch": "tsc --watch" }, "peerDependencies": { + "@medusajs/medusa": ">= 1.18.0 < 2", "medusa-interfaces": "^1.3.7" }, "dependencies": { "analytics-node": "^3.4.0-beta.1", "axios": "^0.19.2", - "body-parser": "^1.19.0", - "express": "^4.17.1", "medusa-core-utils": "^1.2.0" }, "gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e", diff --git a/packages/medusa-plugin-segment/src/subscribers/claim-created.ts b/packages/medusa-plugin-segment/src/subscribers/claim-created.ts new file mode 100644 index 0000000000000..01101ffc06619 --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/claim-created.ts @@ -0,0 +1,46 @@ +export default async function handler({ data: { id }, container }) { + const segmentService = container.resolve("segmentService") + const claimService = container.resolve("claimService") + + const claim = await claimService.retrieve(id, { + relations: [ + "order", + "claim_items", + "claim_items.item", + "claim_items.tags", + "claim_items.variant", + ], + }) + + for (const ci of claim.claim_items) { + const price = ci.item.unit_price / 100 + const reporting_price = await segmentService.getReportingValue( + claim.order.currency_code, + price + ) + const event = { + event: "Item Claimed", + userId: claim.order.customer_id, + timestamp: claim.created_at, + properties: { + price, + reporting_price, + order_id: claim.order_id, + claim_id: claim.id, + claim_item_id: ci.id, + type: claim.type, + quantity: ci.quantity, + variant: ci.variant.sku, + product_id: ci.variant.product_id, + reason: ci.reason, + note: ci.note, + tags: ci.tags.map((t) => ({ id: t.id, value: t.value })), + }, + } + await segmentService.track(event) + } +} + +export const config = { + event: "claim.created", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts b/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts new file mode 100644 index 0000000000000..9c1cf17522e3d --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts @@ -0,0 +1,31 @@ +export default async function handler({ data: { id }, container }) { + const orderService = container.resolve("orderService") + const segmentService = container.resolve("segmentService") + + const order = await orderService.retrieve(id, { + select: [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "gift_card_total", + "subtotal", + "total", + ], + }) + + const date = new Date() + const orderData = await segmentService.buildOrder(order) + const orderEvent = { + event: "Order Cancelled", + userId: order.customer_id, + properties: orderData, + timestamp: date, + } + + segmentService.track(orderEvent) +} + +export const config = { + event: "order.canceled", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts b/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts new file mode 100644 index 0000000000000..01f71d8564ae2 --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts @@ -0,0 +1,91 @@ +export default async function handler({ data: { id, return_id }, container }) { + const orderService = container.resolve("orderService") + const returnService = container.resolve("returnService") + const segmentService = container.resolve("segmentService") + + const order = await orderService.retrieve(id, { + select: [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "gift_card_total", + "subtotal", + "total", + ], + relations: [ + "customer", + "billing_address", + "shipping_address", + "discounts", + "discounts.rule", + "shipping_methods", + "shipping_methods.shipping_option", + "payments", + "fulfillments", + "returns", + "items", + "gift_cards", + "gift_card_transactions", + "swaps", + "swaps.return_order", + "swaps.payment", + "swaps.shipping_methods", + "swaps.shipping_methods.shipping_option", + "swaps.shipping_address", + "swaps.additional_items", + "swaps.fulfillments", + ], + }) + + const ret = await returnService.retrieve(return_id, { + relations: ["items", "items.reason"], + }) + + const shipping: object[] = [] + if (ret.shipping_method && ret.shipping_method.price) { + shipping.push({ + ...ret.shipping_method, + price: -1 * (ret.shipping_method.price / 100), + }) + } + + let merged = [...order.items] + + // merge items from order with items from order swaps + if (order.swaps && order.swaps.length) { + for (const s of order.swaps) { + merged = [...merged, ...s.additional_items] + } + } + + const toBuildFrom = { + ...order, + shipping_methods: shipping, + items: ret.items.map((i) => { + const li = merged.find((l) => l.id === i.item_id) + if (i.reason) { + li.reason = i.reason + } + + if (i.note) { + li.note = i.note + } + return li + }), + } + + const orderData = await segmentService.buildOrder(toBuildFrom) + const orderEvent = { + event: "Order Refunded", + userId: order.customer_id, + properties: orderData, + timestamp: new Date(), + } + + segmentService.track(orderEvent) +} + +export const config = { + event: "order.items-returned", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/order-placed.ts b/packages/medusa-plugin-segment/src/subscribers/order-placed.ts new file mode 100644 index 0000000000000..7a5c1db35ce38 --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/order-placed.ts @@ -0,0 +1,96 @@ +export default async function handler({ data: { id }, container }) { + const orderService = container.resolve("orderService") + const cartService = container.resolve("cartService") + const segmentService = container.resolve("segmentService") + const order = await orderService.retrieve(id, { + select: [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "gift_card_total", + "subtotal", + "total", + ], + relations: [ + "customer", + "billing_address", + "shipping_address", + "discounts", + "discounts.rule", + "shipping_methods", + "shipping_methods.shipping_option", + "payments", + "fulfillments", + "items", + "returns", + "gift_cards", + "gift_card_transactions", + "swaps", + "swaps.return_order", + "swaps.payment", + "swaps.shipping_methods", + "swaps.shipping_methods.shipping_option", + "swaps.shipping_address", + "swaps.additional_items", + "swaps.fulfillments", + ], + }) + + const eventContext: Record = {} + const integrations: Record = {} + + if (order.cart_id) { + try { + const cart = await cartService.retrieve(order.cart_id, { + select: ["context"], + }) + + if (cart.context) { + if (cart.context.ip) { + eventContext.ip = cart.context.ip + } + + if (cart.context.user_agent) { + eventContext.user_agent = cart.context.user_agent + } + + if (segmentService.options_ && segmentService.options_.use_ga_id) { + if (cart.context.ga_id) { + integrations["Google Analytics"] = { + clientId: cart.context.ga_id, + } + } + } + } + } catch (err) { + console.log(err) + console.warn("Failed to gather context for order") + } + } + + const orderData = await segmentService.buildOrder(order) + const orderEvent = { + event: "Order Completed", + userId: order.customer_id, + properties: orderData, + timestamp: order.created_at, + context: eventContext, + integrations, + } + + segmentService.identify({ + userId: order.customer_id, + traits: { + email: order.email, + firstName: order.shipping_address.first_name, + lastName: order.shipping_address.last_name, + }, + }) + + segmentService.track(orderEvent) +} + +export const config = { + event: "order.placed", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts b/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts new file mode 100644 index 0000000000000..ff4ebe20ff25f --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts @@ -0,0 +1,69 @@ +export default async function handler({ + data: { id, fulfillment_id }, + container, +}) { + const orderService = container.resolve("orderService") + const fulfillmentService = container.resolve("fulfillmentService") + const segmentService = container.resolve("segmentService") + + const order = await orderService.retrieve(id, { + select: [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "gift_card_total", + "subtotal", + "total", + ], + relations: [ + "customer", + "billing_address", + "shipping_address", + "discounts", + "discounts.rule", + "shipping_methods", + "shipping_methods.shipping_option", + "payments", + "fulfillments", + "returns", + "items", + "gift_cards", + "gift_card_transactions", + "swaps", + "swaps.return_order", + "swaps.payment", + "swaps.shipping_methods", + "swaps.shipping_methods.shipping_option", + "swaps.shipping_address", + "swaps.additional_items", + "swaps.fulfillments", + ], + }) + + const fulfillment = await fulfillmentService.retrieve(fulfillment_id, { + relations: ["items"], + }) + + const toBuildFrom = { + ...order, + provider_id: fulfillment.provider, + items: fulfillment.items.map((i) => + order.items.find((l) => l.id === i.item_id) + ), + } + + const orderData = await segmentService.buildOrder(toBuildFrom) + const orderEvent = { + event: "Order Shipped", + userId: order.customer_id, + properties: orderData, + timestamp: fulfillment.shipped_at, + } + + segmentService.track(orderEvent) +} + +export const config = { + event: "order.shipment_created", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/order.js b/packages/medusa-plugin-segment/src/subscribers/order.js deleted file mode 100644 index 3c13b334a5ce7..0000000000000 --- a/packages/medusa-plugin-segment/src/subscribers/order.js +++ /dev/null @@ -1,338 +0,0 @@ -class OrderSubscriber { - constructor({ - segmentService, - eventBusService, - orderService, - cartService, - claimService, - returnService, - fulfillmentService, - }) { - this.orderService_ = orderService - - this.cartService_ = cartService - - this.returnService_ = returnService - - this.claimService_ = claimService - - this.fulfillmentService_ = fulfillmentService - - // Swaps - // swap.created - // swap.received - // swap.shipment_created - // swap.payment_completed - // swap.payment_captured - // swap.refund_processed - - eventBusService.subscribe( - "order.shipment_created", - async ({ id, fulfillment_id }) => { - const order = await this.orderService_.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], - relations: [ - "customer", - "billing_address", - "shipping_address", - "discounts", - "discounts.rule", - "shipping_methods", - "shipping_methods.shipping_option", - "payments", - "fulfillments", - "returns", - "items", - "gift_cards", - "gift_card_transactions", - "swaps", - "swaps.return_order", - "swaps.payment", - "swaps.shipping_methods", - "swaps.shipping_methods.shipping_option", - "swaps.shipping_address", - "swaps.additional_items", - "swaps.fulfillments", - ], - }) - - const fulfillment = await this.fulfillmentService_.retrieve( - fulfillment_id, - { - relations: ["items"], - } - ) - - const toBuildFrom = { - ...order, - provider_id: fulfillment.provider, - items: fulfillment.items.map((i) => - order.items.find((l) => l.id === i.item_id) - ), - } - - const orderData = await segmentService.buildOrder(toBuildFrom) - const orderEvent = { - event: "Order Shipped", - userId: order.customer_id, - properties: orderData, - timestamp: fulfillment.shipped_at, - } - - segmentService.track(orderEvent) - } - ) - - eventBusService.subscribe("claim.created", async ({ id }) => { - const claim = await this.claimService_.retrieve(id, { - relations: [ - "order", - "claim_items", - "claim_items.item", - "claim_items.tags", - "claim_items.variant", - ], - }) - - for (const ci of claim.claim_items) { - const price = ci.item.unit_price / 100 - const reporting_price = await segmentService.getReportingValue( - claim.order.currency_code, - price - ) - const event = { - event: "Item Claimed", - userId: claim.order.customer_id, - timestamp: claim.created_at, - properties: { - price, - reporting_price, - order_id: claim.order_id, - claim_id: claim.id, - claim_item_id: ci.id, - type: claim.type, - quantity: ci.quantity, - variant: ci.variant.sku, - product_id: ci.variant.product_id, - reason: ci.reason, - note: ci.note, - tags: ci.tags.map((t) => ({ id: t.id, value: t.value })), - }, - } - await segmentService.track(event) - } - }) - - eventBusService.subscribe( - "order.items_returned", - async ({ id, return_id }) => { - const order = await this.orderService_.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], - relations: [ - "customer", - "billing_address", - "shipping_address", - "discounts", - "discounts.rule", - "shipping_methods", - "shipping_methods.shipping_option", - "payments", - "fulfillments", - "returns", - "items", - "gift_cards", - "gift_card_transactions", - "swaps", - "swaps.return_order", - "swaps.payment", - "swaps.shipping_methods", - "swaps.shipping_methods.shipping_option", - "swaps.shipping_address", - "swaps.additional_items", - "swaps.fulfillments", - ], - }) - - const ret = await this.returnService_.retrieve(return_id, { - relations: ["items", "items.reason"], - }) - - const shipping = [] - if (ret.shipping_method && ret.shipping_method.price) { - shipping.push({ - ...ret.shipping_method, - price: -1 * (ret.shipping_method.price / 100), - }) - } - - let merged = [...order.items] - - // merge items from order with items from order swaps - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - const toBuildFrom = { - ...order, - shipping_methods: shipping, - items: ret.items.map((i) => { - const li = merged.find((l) => l.id === i.item_id) - if (i.reason) { - li.reason = i.reason - } - - if (i.note) { - li.note = i.note - } - return li - }), - } - - const orderData = await segmentService.buildOrder(toBuildFrom) - const orderEvent = { - event: "Order Refunded", - userId: order.customer_id, - properties: orderData, - timestamp: new Date(), - } - - segmentService.track(orderEvent) - } - ) - - eventBusService.subscribe("order.canceled", async ({ id }) => { - const order = await this.orderService_.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], - }) - - const date = new Date() - const orderData = await segmentService.buildOrder(order) - const orderEvent = { - event: "Order Cancelled", - userId: order.customer_id, - properties: orderData, - timestamp: date, - } - - segmentService.track(orderEvent) - }) - - eventBusService.subscribe("order.placed", async ({ id }) => { - const order = await this.orderService_.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], - relations: [ - "customer", - "billing_address", - "shipping_address", - "discounts", - "discounts.rule", - "shipping_methods", - "shipping_methods.shipping_option", - "payments", - "fulfillments", - "items", - "returns", - "gift_cards", - "gift_card_transactions", - "swaps", - "swaps.return_order", - "swaps.payment", - "swaps.shipping_methods", - "swaps.shipping_methods.shipping_option", - "swaps.shipping_address", - "swaps.additional_items", - "swaps.fulfillments", - ], - }) - - const eventContext = {} - const integrations = {} - - if (order.cart_id) { - try { - const cart = await this.cartService_.retrieve(order.cart_id, { - select: ["context"], - }) - - if (cart.context) { - if (cart.context.ip) { - eventContext.ip = cart.context.ip - } - - if (cart.context.user_agent) { - eventContext.user_agent = cart.context.user_agent - } - - if (segmentService.options_ && segmentService.options_.use_ga_id) { - if (cart.context.ga_id) { - integrations["Google Analytics"] = { - clientId: cart.context.ga_id, - } - } - } - } - } catch (err) { - console.log(err) - console.warn("Failed to gather context for order") - } - } - - const orderData = await segmentService.buildOrder(order) - const orderEvent = { - event: "Order Completed", - userId: order.customer_id, - properties: orderData, - timestamp: order.created_at, - context: eventContext, - integrations, - } - - segmentService.identify({ - userId: order.customer_id, - traits: { - email: order.email, - firstName: order.shipping_address.first_name, - lastName: order.shipping_address.last_name, - }, - }) - - segmentService.track(orderEvent) - }) - } -} - -export default OrderSubscriber diff --git a/packages/medusa-plugin-segment/src/subscribers/swap-created.ts b/packages/medusa-plugin-segment/src/subscribers/swap-created.ts new file mode 100644 index 0000000000000..ca2be09343686 --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/swap-created.ts @@ -0,0 +1,24 @@ +import { gatherSwapReport } from "../utils/gather-swap-report" + +export default async function handler({ data: { id }, container }) { + const swapService = container.resolve("swapService") + const segmentService = container.resolve("segmentService") + const lineItemService = container.resolve("lineItemService") + + const [swap, swapReport] = await gatherSwapReport(id, { + swapService, + segmentService, + lineItemService, + }) + + return await segmentService.track({ + event: "Swap Created", + userId: swap.order.customer_id, + timestamp: swap.created_at, + properties: swapReport, + }) +} + +export const config = { + event: "swap.created", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/swap-payment-completed.ts b/packages/medusa-plugin-segment/src/subscribers/swap-payment-completed.ts new file mode 100644 index 0000000000000..c06ddecfa654e --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/swap-payment-completed.ts @@ -0,0 +1,36 @@ +import { humanizeAmount } from "medusa-core-utils" +import { gatherSwapReport } from "../utils/gather-swap-report" + +export default async function handler({ data: { id }, container }) { + const swapService = container.resolve("swapService") + const segmentService = container.resolve("segmentService") + const lineItemService = container.resolve("lineItemService") + + const [swap, swapReport] = await gatherSwapReport(id, { + swapService, + segmentService, + lineItemService, + }) + + const currency = swapReport.currency + const total = humanizeAmount(swap.difference_due, currency) + const reporting_total = await segmentService.getReportingValue( + currency, + total + ) + + return await segmentService.track({ + event: "Swap Confirmed", + userId: swap.order.customer_id, + timestamp: swap.confirmed_at, + properties: { + reporting_total, + total, + ...swapReport, + }, + }) +} + +export const config = { + event: "swap.payment_completed", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/swap-shipment-created.ts b/packages/medusa-plugin-segment/src/subscribers/swap-shipment-created.ts new file mode 100644 index 0000000000000..06b2a6957a8ed --- /dev/null +++ b/packages/medusa-plugin-segment/src/subscribers/swap-shipment-created.ts @@ -0,0 +1,41 @@ +import { humanizeAmount } from "medusa-core-utils" +import { gatherSwapReport } from "../utils/gather-swap-report" + +export default async function handler({ + data: { id, fulfillment_id }, + container, +}) { + const segmentService = container.resolve("segmentService") + const fulfillmentService = container.resolve("fulfillmentService") + const swapService = container.resolve("swapService") + const lineItemService = container.resolve("lineItemService") + + const [swap, swapReport] = await gatherSwapReport(id, { + swapService, + segmentService, + lineItemService, + }) + const fulfillment = await fulfillmentService.retrieve(fulfillment_id) + + const currency = swapReport.currency + const total = humanizeAmount(swap.difference_due, currency) + const reporting_total = await segmentService.getReportingValue( + currency, + total + ) + + return await segmentService.track({ + event: "Swap Shipped", + userId: swap.order.customer_id, + timestamp: fulfillment.shipped_at, + properties: { + reporting_total, + total, + ...swapReport, + }, + }) +} + +export const config = { + event: "swap.shipment_created", +} diff --git a/packages/medusa-plugin-segment/src/subscribers/swap.js b/packages/medusa-plugin-segment/src/subscribers/swap.js deleted file mode 100644 index 30c83d0b91afd..0000000000000 --- a/packages/medusa-plugin-segment/src/subscribers/swap.js +++ /dev/null @@ -1,149 +0,0 @@ -import { humanizeAmount } from "medusa-core-utils" - -class OrderSubscriber { - constructor({ - segmentService, - eventBusService, - swapService, - lineItemService, - fulfillmentService, - }) { - this.fulfillmentService_ = fulfillmentService - - this.lineItemService_ = lineItemService - - this.swapService_ = swapService - - this.segmentService_ = segmentService - - eventBusService.subscribe( - "swap.shipment_created", - async ({ id, fulfillment_id }) => { - const [swap, swapReport] = await this.gatherSwapReport(id) - const fulfillment = await this.fulfillmentService_.retrieve( - fulfillment_id - ) - - const currency = swapReport.currency - const total = humanizeAmount(swap.difference_due, currency) - const reporting_total = await this.segmentService_.getReportingValue( - currency, - total - ) - - return await segmentService.track({ - event: "Swap Shipped", - userId: swap.order.customer_id, - timestamp: fulfillment.shipped_at, - properties: { - reporting_total, - total, - ...swapReport, - }, - }) - } - ) - - eventBusService.subscribe("swap.payment_completed", async ({ id }) => { - const [swap, swapReport] = await this.gatherSwapReport(id) - - const currency = swapReport.currency - const total = humanizeAmount(swap.difference_due, currency) - const reporting_total = await this.segmentService_.getReportingValue( - currency, - total - ) - - return await segmentService.track({ - event: "Swap Confirmed", - userId: swap.order.customer_id, - timestamp: swap.confirmed_at, - properties: { - reporting_total, - total, - ...swapReport, - }, - }) - }) - - eventBusService.subscribe("swap.created", async ({ id }) => { - const [swap, swapReport] = await this.gatherSwapReport(id) - - return await segmentService.track({ - event: "Swap Created", - userId: swap.order.customer_id, - timestamp: swap.created_at, - properties: swapReport, - }) - }) - } - - async gatherSwapReport(id) { - const swap = await this.swapService_.retrieve(id, { - relations: [ - "order", - "additional_items", - "additional_items.variant", - "return_order", - "return_order.items", - "return_order.shipping_method", - ], - }) - - const currency = swap.order.currency_code - - const newItems = await Promise.all( - swap.additional_items.map(async (i) => { - const price = humanizeAmount(i.unit_price, currency) - const reporting_price = await this.segmentService_.getReportingValue( - currency, - price - ) - - return { - name: i.title, - product_id: i.variant.product_id, - variant: i.variant.sku, - quantity: i.quantity, - price, - reporting_price, - } - }) - ) - - const returnItems = await Promise.all( - swap.return_order.items.map(async (ri) => { - const i = await this.lineItemService_.retrieve(ri.item_id, { - relations: ["variant"], - }) - const price = humanizeAmount(i.unit_price, currency) - const reporting_price = await this.segmentService_.getReportingValue( - currency, - price - ) - - return { - name: i.title, - product_id: i.variant.product_id, - variant: i.variant.sku, - quantity: ri.quantity, - price, - reporting_price, - } - }) - ) - - return [ - swap, - { - swap_id: swap.id, - order_id: swap.order_id, - new_items: newItems, - return_items: returnItems, - currency, - }, - ] - } -} - -export default OrderSubscriber diff --git a/packages/medusa-plugin-segment/src/utils/gather-swap-report.ts b/packages/medusa-plugin-segment/src/utils/gather-swap-report.ts new file mode 100644 index 0000000000000..3055b8e33aedc --- /dev/null +++ b/packages/medusa-plugin-segment/src/utils/gather-swap-report.ts @@ -0,0 +1,71 @@ +import { humanizeAmount } from "medusa-core-utils" + +export async function gatherSwapReport( + id, + { swapService, segmentService, lineItemService } +) { + const swap = await swapService.retrieve(id, { + relations: [ + "order", + "additional_items", + "additional_items.variant", + "return_order", + "return_order.items", + "return_order.shipping_method", + ], + }) + + const currency = swap.order.currency_code + + const newItems = await Promise.all( + swap.additional_items.map(async (i) => { + const price = humanizeAmount(i.unit_price, currency) + const reporting_price = await segmentService.getReportingValue( + currency, + price + ) + + return { + name: i.title, + product_id: i.variant.product_id, + variant: i.variant.sku, + quantity: i.quantity, + price, + reporting_price, + } + }) + ) + + const returnItems = await Promise.all( + swap.return_order.items.map(async (ri) => { + const i = await lineItemService.retrieve(ri.item_id, { + relations: ["variant"], + }) + const price = humanizeAmount(i.unit_price, currency) + const reporting_price = await segmentService.getReportingValue( + currency, + price + ) + + return { + name: i.title, + product_id: i.variant.product_id, + variant: i.variant.sku, + quantity: ri.quantity, + price, + reporting_price, + } + }) + ) + + return [ + swap, + { + swap_id: swap.id, + order_id: swap.order_id, + new_items: newItems, + return_items: returnItems, + currency, + }, + ] +} diff --git a/packages/medusa-plugin-segment/tsconfig.admin.json b/packages/medusa-plugin-segment/tsconfig.admin.json new file mode 100644 index 0000000000000..b109ee6f17f3b --- /dev/null +++ b/packages/medusa-plugin-segment/tsconfig.admin.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "esnext" + }, + "include": ["src/admin"], + "exclude": ["**/*.spec.js"] +} diff --git a/packages/medusa-plugin-segment/tsconfig.json b/packages/medusa-plugin-segment/tsconfig.json new file mode 100644 index 0000000000000..869a718e13d56 --- /dev/null +++ b/packages/medusa-plugin-segment/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "lib": [ + "es5", + "es6", + "es2019" + ], + "target": "es5", + "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, + "outDir": "./dist", + "esModuleInterop": true, + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "downlevelIteration": true // to use ES5 specific tooling + }, + "include": ["src"], + "exclude": [ + "dist", + "build", + "src/**/__tests__", + "src/**/__mocks__", + "src/**/__fixtures__", + "node_modules", + ".eslintrc.js" + ] +} diff --git a/packages/medusa-plugin-segment/tsconfig.server.json b/packages/medusa-plugin-segment/tsconfig.server.json new file mode 100644 index 0000000000000..0a84ca8c0c8d9 --- /dev/null +++ b/packages/medusa-plugin-segment/tsconfig.server.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */ + }, + "exclude": ["src/admin", "**/*.spec.js"] +} diff --git a/packages/medusa-plugin-segment/tsconfig.spec.json b/packages/medusa-plugin-segment/tsconfig.spec.json new file mode 100644 index 0000000000000..9b6240919113c --- /dev/null +++ b/packages/medusa-plugin-segment/tsconfig.spec.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock index 48d14724f8a2b..c8134ee1bfa93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36134,27 +36134,18 @@ __metadata: version: 0.0.0-use.local resolution: "medusa-plugin-segment@workspace:packages/medusa-plugin-segment" dependencies: - "@babel/cli": ^7.7.5 - "@babel/core": ^7.7.5 - "@babel/node": ^7.7.4 - "@babel/plugin-proposal-class-properties": ^7.7.4 - "@babel/plugin-transform-classes": ^7.9.5 - "@babel/plugin-transform-instanceof": ^7.8.3 - "@babel/plugin-transform-runtime": ^7.7.6 - "@babel/preset-env": ^7.7.5 - "@babel/register": ^7.7.4 - "@babel/runtime": ^7.9.6 analytics-node: ^3.4.0-beta.1 axios: ^0.19.2 - body-parser: ^1.19.0 cross-env: ^5.2.1 eslint: ^6.8.0 - express: ^4.17.1 jest: ^25.5.4 medusa-core-utils: ^1.2.0 medusa-interfaces: ^1.3.7 medusa-test-utils: ^1.1.40 + rimraf: ^5.0.1 + typescript: ^4.9.5 peerDependencies: + "@medusajs/medusa": ">= 1.18.0 < 2" medusa-interfaces: ^1.3.7 languageName: unknown linkType: soft From 1c8264c4a11f4b002513b6ad87ac06295613dd2e Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Sat, 16 Dec 2023 18:02:50 +0100 Subject: [PATCH 2/4] fix: admin --- packages/medusa-plugin-segment/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/medusa-plugin-segment/package.json b/packages/medusa-plugin-segment/package.json index 81a08fc987eda..9b1d5b63dc591 100644 --- a/packages/medusa-plugin-segment/package.json +++ b/packages/medusa-plugin-segment/package.json @@ -25,7 +25,7 @@ "scripts": { "prepublishOnly": "cross-env NODE_ENV=production tsc --build", "test": "jest --passWithNoTests src", - "build": "rimraf dist && tsc -p ./tsconfig.server.json && medusa-admin bundle", + "build": "rimraf dist && tsc -p ./tsconfig.server.json", "watch": "tsc --watch" }, "peerDependencies": { From 1a090f56902964b9aeeb26a755ab72890ea5a662 Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Fri, 12 Jan 2024 10:33:57 +0100 Subject: [PATCH 3/4] fix: use retrieveWithTotals --- .../src/subscribers/order-canceled.ts | 12 +----------- .../src/subscribers/order-items-returned.ts | 11 +---------- .../src/subscribers/order-placed.ts | 11 +---------- .../src/subscribers/order-shipment-created.ts | 11 +---------- 4 files changed, 4 insertions(+), 41 deletions(-) diff --git a/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts b/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts index 9c1cf17522e3d..daaa23335141d 100644 --- a/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts +++ b/packages/medusa-plugin-segment/src/subscribers/order-canceled.ts @@ -2,17 +2,7 @@ export default async function handler({ data: { id }, container }) { const orderService = container.resolve("orderService") const segmentService = container.resolve("segmentService") - const order = await orderService.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], - }) + const order = await orderService.retrieveWithTotals(id) const date = new Date() const orderData = await segmentService.buildOrder(order) diff --git a/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts b/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts index 01f71d8564ae2..07012730ea596 100644 --- a/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts +++ b/packages/medusa-plugin-segment/src/subscribers/order-items-returned.ts @@ -3,16 +3,7 @@ export default async function handler({ data: { id, return_id }, container }) { const returnService = container.resolve("returnService") const segmentService = container.resolve("segmentService") - const order = await orderService.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], + const order = await orderService.retrieveWithTotals(id, { relations: [ "customer", "billing_address", diff --git a/packages/medusa-plugin-segment/src/subscribers/order-placed.ts b/packages/medusa-plugin-segment/src/subscribers/order-placed.ts index 7a5c1db35ce38..044d4637ed6fd 100644 --- a/packages/medusa-plugin-segment/src/subscribers/order-placed.ts +++ b/packages/medusa-plugin-segment/src/subscribers/order-placed.ts @@ -2,16 +2,7 @@ export default async function handler({ data: { id }, container }) { const orderService = container.resolve("orderService") const cartService = container.resolve("cartService") const segmentService = container.resolve("segmentService") - const order = await orderService.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], + const order = await orderService.retrieveWithTotals(id, { relations: [ "customer", "billing_address", diff --git a/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts b/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts index ff4ebe20ff25f..1428acdff4cdb 100644 --- a/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts +++ b/packages/medusa-plugin-segment/src/subscribers/order-shipment-created.ts @@ -6,16 +6,7 @@ export default async function handler({ const fulfillmentService = container.resolve("fulfillmentService") const segmentService = container.resolve("segmentService") - const order = await orderService.retrieve(id, { - select: [ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - ], + const order = await orderService.retrieveWithTotals(id, { relations: [ "customer", "billing_address", From 088738a7d5527e24fe2e87a6370642c547ac4252 Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Thu, 18 Jan 2024 10:26:46 +0100 Subject: [PATCH 4/4] fix: don't fail if order has no shipping address --- packages/medusa-plugin-segment/src/services/segment.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/medusa-plugin-segment/src/services/segment.js b/packages/medusa-plugin-segment/src/services/segment.js index caaae460e43da..9fa275de4fb7c 100644 --- a/packages/medusa-plugin-segment/src/services/segment.js +++ b/packages/medusa-plugin-segment/src/services/segment.js @@ -78,10 +78,10 @@ class SegmentService extends BaseService { order_id: order.id, email: order.email, region_id: order.region_id, - payment_provider: order.payments.map((p) => p.provider_id).join(","), + payment_provider: order.payments?.map((p) => p.provider_id).join(","), shipping_methods: order.shipping_methods, - shipping_country: order.shipping_address.country_code, - shipping_city: order.shipping_address.city, + shipping_country: order.shipping_address?.country_code, + shipping_city: order.shipping_address?.city, reporting_total: await this.getReportingValue(order.currency_code, total), reporting_subtotal: await this.getReportingValue( order.currency_code,