From c8724da50300b94255c5fb4ffe9904be279b5923 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Mon, 19 Dec 2022 15:37:35 +0100 Subject: [PATCH] feat(medusa,medusa-payment-stripe): Move database mutation from plugin to core (#2743) **what** The goal of that PR is to first refactor the payment provider and payment plugin to support the new API that removes the data mutation from within the plugin to be done by the core instead. In any case, this pr does not include the steps of the deeper refactoring. The last part will come in later pr. **How** - The payment plugin is now capable to handle both the deprecated and new API and the plugin works the same as it use to works. - The mutation made by the plugin have been moved into the core as well as the subscriber - The tests have been updated to reflect the changed - Remove all new methods introduced by the payment collections - Mutualise types - Update provider and payment collection services - cleanup around all those refactoring including cleanup of the payment collection - refactor stripe payment plugin FIXES CORE-887 --- .changeset/strong-radios-scream.md | 6 + .eslintignore | 3 - .../admin/__snapshots__/price-list.js.snap | 31 -- .../api/__tests__/admin/price-list.js | 54 +-- packages/medusa-core-utils/src/index.ts | 1 + .../src}/is-defined.ts | 0 packages/medusa-payment-stripe/package.json | 4 +- .../src/__mocks__/cart.js | 2 + .../src/__mocks__/stripe.js | 4 +- .../__tests__/stripe-base.js} | 192 ++++---- .../src/helpers/stripe-base.js | 279 +++++++----- .../src/services/__mocks__/stripe-provider.js | 55 --- .../src/services/stripe-bancontact.js | 22 +- .../src/services/stripe-blik.js | 22 +- .../src/services/stripe-giropay.js | 22 +- .../src/services/stripe-ideal.js | 22 +- .../src/services/stripe-provider.js | 422 +----------------- .../src/services/stripe-przelewy24.js | 22 +- .../src/subscribers/cart.js | 60 --- .../utils/eu-countries.js | 0 .../api/routes/admin/batch/list-batch-jobs.ts | 2 +- .../admin/gift-cards/list-gift-cards.ts | 2 +- .../api/routes/admin/orders/request-return.ts | 3 +- .../price-lists/list-price-list-products.ts | 2 +- .../routes/admin/returns/receive-return.ts | 2 +- .../routes/admin/tax-rates/create-tax-rate.ts | 3 +- .../routes/admin/tax-rates/update-tax-rate.ts | 2 +- .../admin/tax-rates/utils/get-query-config.ts | 2 +- .../src/api/routes/store/carts/create-cart.ts | 3 +- .../routes/store/products/list-products.ts | 3 +- .../controllers/customers/list-customers.ts | 2 +- .../medusa/src/interfaces/payment-service.ts | 67 ++- .../medusa/src/loaders/feature-flags/index.ts | 2 +- packages/medusa/src/loaders/services.ts | 2 +- packages/medusa/src/loaders/strategies.ts | 2 +- packages/medusa/src/models/payment-session.ts | 13 +- .../src/repositories/payment-collection.ts | 9 - packages/medusa/src/repositories/tax-rate.ts | 21 +- .../services/__fixtures__/payment-provider.ts | 18 + .../services/__mocks__/payment-provider.js | 35 +- .../medusa/src/services/__tests__/cart.js | 18 +- .../services/__tests__/payment-collection.ts | 67 ++- .../services/__tests__/payment-provider.js | 225 ++++++---- packages/medusa/src/services/batch-job.ts | 4 +- packages/medusa/src/services/cart.ts | 43 +- packages/medusa/src/services/claim-item.ts | 4 +- packages/medusa/src/services/claim.ts | 4 +- .../medusa/src/services/customer-group.ts | 11 +- packages/medusa/src/services/customer.ts | 4 +- .../medusa/src/services/discount-condition.ts | 4 +- packages/medusa/src/services/discount.ts | 4 +- packages/medusa/src/services/draft-order.ts | 4 +- packages/medusa/src/services/fulfillment.ts | 4 +- packages/medusa/src/services/gift-card.ts | 4 +- .../medusa/src/services/idempotency-key.ts | 3 +- packages/medusa/src/services/inventory.ts | 3 +- .../src/services/line-item-adjustment.ts | 4 +- packages/medusa/src/services/new-totals.ts | 4 +- packages/medusa/src/services/note.ts | 4 +- packages/medusa/src/services/oauth.ts | 4 +- packages/medusa/src/services/order-edit.ts | 4 +- packages/medusa/src/services/order.ts | 7 +- .../medusa/src/services/payment-collection.ts | 138 +++--- .../medusa/src/services/payment-provider.ts | 375 +++++++++------- packages/medusa/src/services/payment.ts | 4 +- packages/medusa/src/services/price-list.ts | 4 +- .../medusa/src/services/product-collection.ts | 4 +- .../medusa/src/services/product-variant.ts | 4 +- packages/medusa/src/services/product.ts | 4 +- .../src/services/publishable-api-key.ts | 4 +- packages/medusa/src/services/region.ts | 4 +- packages/medusa/src/services/return-reason.ts | 6 +- packages/medusa/src/services/return.ts | 3 +- packages/medusa/src/services/sales-channel.ts | 4 +- .../medusa/src/services/shipping-option.ts | 4 +- .../medusa/src/services/shipping-profile.ts | 4 +- packages/medusa/src/services/swap.ts | 4 +- packages/medusa/src/services/tax-rate.ts | 14 +- packages/medusa/src/services/totals.ts | 4 +- packages/medusa/src/services/user.ts | 4 +- .../medusa/src/strategies/price-selection.ts | 2 +- packages/medusa/src/subscribers/cart.ts | 70 +++ .../medusa/src/types/payment-collection.ts | 16 +- packages/medusa/src/types/payment.ts | 34 ++ packages/medusa/src/utils/get-query-config.ts | 3 +- packages/medusa/src/utils/index.ts | 1 - .../src/utils/remove-undefined-properties.ts | 2 +- 87 files changed, 1138 insertions(+), 1429 deletions(-) create mode 100644 .changeset/strong-radios-scream.md rename packages/{medusa/src/utils => medusa-core-utils/src}/is-defined.ts (100%) rename packages/medusa-payment-stripe/src/{services/__tests__/stripe-provider.js => helpers/__tests__/stripe-base.js} (51%) delete mode 100644 packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js delete mode 100644 packages/medusa-payment-stripe/src/subscribers/cart.js mode change 100755 => 100644 packages/medusa-plugin-economic/utils/eu-countries.js create mode 100644 packages/medusa/src/services/__fixtures__/payment-provider.ts create mode 100644 packages/medusa/src/subscribers/cart.ts create mode 100644 packages/medusa/src/types/payment.ts diff --git a/.changeset/strong-radios-scream.md b/.changeset/strong-radios-scream.md new file mode 100644 index 0000000000..ffde62a009 --- /dev/null +++ b/.changeset/strong-radios-scream.md @@ -0,0 +1,6 @@ +--- +"medusa-payment-stripe": patch +"@medusajs/medusa": patch +--- + +feat(medusa,medusa-payment-stripe): Move database mutation from plugin to core diff --git a/.eslintignore b/.eslintignore index d74f74baf2..83458b3442 100644 --- a/.eslintignore +++ b/.eslintignore @@ -8,8 +8,6 @@ packages/* # List of packages to Lint !packages/medusa -integration-tests/* -#!integration-tests/api **/models/* @@ -18,6 +16,5 @@ integration-tests/* **/node_modules/* **/migrations/* **/__mocks__/* -**/__tests__/* .eslintrc.js diff --git a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap index 287c4f6b99..5d7eb27d4a 100644 --- a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap +++ b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap @@ -149,37 +149,6 @@ Object { } `; -exports[`/admin/price-lists POST /admin/price-lists/:id updates price list prices (inser a new MA for a specific region) 1`] = ` -Array [ - Object { - "amount": 101, - "created_at": Any, - "currency_code": "eur", - "deleted_at": null, - "id": Any, - "max_quantity": null, - "min_quantity": null, - "price_list_id": "pl_with_some_ma", - "region_id": "region-pl", - "updated_at": Any, - "variant_id": "test-variant", - }, - Object { - "amount": 1001, - "created_at": Any, - "currency_code": "usd", - "deleted_at": null, - "id": "ma_test_4", - "max_quantity": null, - "min_quantity": null, - "price_list_id": "pl_with_some_ma", - "region_id": null, - "updated_at": Any, - "variant_id": "test-variant", - }, -] -`; - exports[`/admin/price-lists POST /admin/price-lists/:id updates the amount and currency of a price in the price list 1`] = ` Object { "amount": 250, diff --git a/integration-tests/api/__tests__/admin/price-list.js b/integration-tests/api/__tests__/admin/price-list.js index ddbbcffb04..b4647575bd 100644 --- a/integration-tests/api/__tests__/admin/price-list.js +++ b/integration-tests/api/__tests__/admin/price-list.js @@ -638,32 +638,34 @@ describe("/admin/price-lists", () => { expect(response.status).toEqual(200) expect(response.data.price_list.prices.length).toEqual(2) - expect(response.data.price_list.prices).toMatchSnapshot([ - { - id: expect.any(String), - currency_code: "eur", - amount: 101, - min_quantity: null, - max_quantity: null, - price_list_id: "pl_with_some_ma", - variant_id: "test-variant", - region_id: "region-pl", - created_at: expect.any(String), - updated_at: expect.any(String), - deleted_at: null, - }, - { - id: "ma_test_4", - currency_code: "usd", - amount: 1001, - price_list_id: "pl_with_some_ma", - variant_id: "test-variant", - region_id: null, - created_at: expect.any(String), - updated_at: expect.any(String), - deleted_at: null, - }, - ]) + expect(response.data.price_list.prices).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + currency_code: "eur", + amount: 101, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: "region-pl", + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }), + expect.objectContaining({ + id: "ma_test_4", + currency_code: "usd", + amount: 1001, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }), + ]) + ) }) }) diff --git a/packages/medusa-core-utils/src/index.ts b/packages/medusa-core-utils/src/index.ts index 0a5caa85b4..270aa175d8 100644 --- a/packages/medusa-core-utils/src/index.ts +++ b/packages/medusa-core-utils/src/index.ts @@ -10,4 +10,5 @@ export { parseCorsOrigins } from "./parse-cors-origins" export { transformIdableFields } from "./transform-idable-fields" export { default as Validator } from "./validator" export { default as zeroDecimalCurrencies } from "./zero-decimal-currencies" +export * from "./is-defined" diff --git a/packages/medusa/src/utils/is-defined.ts b/packages/medusa-core-utils/src/is-defined.ts similarity index 100% rename from packages/medusa/src/utils/is-defined.ts rename to packages/medusa-core-utils/src/is-defined.ts diff --git a/packages/medusa-payment-stripe/package.json b/packages/medusa-payment-stripe/package.json index 37339a50a8..297cd72bff 100644 --- a/packages/medusa-payment-stripe/package.json +++ b/packages/medusa-payment-stripe/package.json @@ -29,9 +29,9 @@ "medusa-test-utils": "^1.1.37" }, "scripts": { - "build": "babel src -d . --ignore **/__tests__", + "build": "babel src -d . --ignore **/__tests__ --ignore **/__mocks__", "prepare": "cross-env NODE_ENV=production yarn run build", - "watch": "babel -w src --out-dir . --ignore **/__tests__", + "watch": "babel -w src --out-dir . --ignore **/__tests__ --ignore **/__mocks__", "test": "jest" }, "peerDependencies": { diff --git a/packages/medusa-payment-stripe/src/__mocks__/cart.js b/packages/medusa-payment-stripe/src/__mocks__/cart.js index c3a5bd01d0..c301361bda 100644 --- a/packages/medusa-payment-stripe/src/__mocks__/cart.js +++ b/packages/medusa-payment-stripe/src/__mocks__/cart.js @@ -91,6 +91,8 @@ export const carts = { customer: IdMap.getId("not-lebron"), }, }, + region: { currency_code: "usd" }, + total: 100, shipping_address: {}, billing_address: {}, discounts: [], diff --git a/packages/medusa-payment-stripe/src/__mocks__/stripe.js b/packages/medusa-payment-stripe/src/__mocks__/stripe.js index 23b250a650..deb6bafc85 100644 --- a/packages/medusa-payment-stripe/src/__mocks__/stripe.js +++ b/packages/medusa-payment-stripe/src/__mocks__/stripe.js @@ -20,7 +20,7 @@ export const StripeMock = { if (data.customer === "cus_123456789_new") { return Promise.resolve({ id: "pi_lebron", - amount: 100, + amount: data.amount, customer: "cus_123456789_new", description: data?.description, }) @@ -28,7 +28,7 @@ export const StripeMock = { if (data.customer === "cus_lebron") { return Promise.resolve({ id: "pi_lebron", - amount: 100, + amount: data.amount, customer: "cus_lebron", description: data?.description, }) diff --git a/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js b/packages/medusa-payment-stripe/src/helpers/__tests__/stripe-base.js similarity index 51% rename from packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js rename to packages/medusa-payment-stripe/src/helpers/__tests__/stripe-base.js index b6eed7d2e2..7bd3cf247d 100644 --- a/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js +++ b/packages/medusa-payment-stripe/src/helpers/__tests__/stripe-base.js @@ -1,58 +1,13 @@ -import { IdMap } from "medusa-test-utils" -import StripeProviderService from "../stripe-provider" -import { CustomerServiceMock } from "../../__mocks__/customer" import { carts } from "../../__mocks__/cart" -import { TotalsServiceMock } from "../../__mocks__/totals" +import StripeBase from "../stripe-base"; -const RegionServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockReturnValue(Promise.resolve({})), -} - -describe("StripeProviderService", () => { - describe("createCustomer", () => { - let result - beforeAll(async () => { - jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - { - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, - { - api_key: "test", - } - ) - - result = await stripeProviderService.createCustomer({ - _id: IdMap.getId("vvd"), - first_name: "Virgil", - last_name: "Van Dijk", - email: "virg@vvd.com", - password_hash: "1234", - metadata: {}, - }) - }) - - it("returns created stripe customer", () => { - expect(result).toEqual({ - id: "cus_vvd", - email: "virg@vvd.com", - }) - }) - }) +const fakeContainer = {} +describe("StripeBase", () => { describe("createPayment", () => { let result - const stripeProviderService = new StripeProviderService( - { - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test" } @@ -63,45 +18,88 @@ describe("StripeProviderService", () => { }) it("returns created stripe payment intent for cart with existing customer", async () => { - result = await stripeProviderService.createPayment(carts.frCart) + const cart = carts.frCart + const context = { + cart, + amount: cart.total, + currency_code: cart.region?.currency_code, + } + Object.assign(context, cart) + + result = await stripeBase.createPayment(context) expect(result).toEqual({ - id: "pi_lebron", - customer: "cus_123456789_new", - amount: 100, + session_data: { + id: "pi_lebron", + customer: "cus_lebron", + description: undefined, + amount: 100, + }, + update_requests: { + customer_metadata: { + stripe_id: "cus_lebron" + } + } }) }) it("returns created stripe payment intent for cart with no customer", async () => { - carts.frCart.customer_id = "" - carts.frCart.context.payment_description = 'some description' - result = await stripeProviderService.createPayment(carts.frCart) + const cart = carts.frCart + const context = { + cart, + amount: cart.total, + currency_code: cart.region?.currency_code, + } + Object.assign(context, cart) + + context.cart.context.payment_description = 'some description' + + result = await stripeBase.createPayment(context) expect(result).toEqual({ - id: "pi_lebron", - customer: "cus_lebron", - amount: 100, - description: 'some description', + session_data: { + id: "pi_lebron", + customer: "cus_lebron", + description: 'some description', + amount: 100, + }, + update_requests: { + customer_metadata: { + stripe_id: "cus_lebron" + } + } }) }) it("returns created stripe payment intent for cart with no customer and the options default description", async () => { - const localStripeProviderService = new StripeProviderService({ - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, + const localStripeProviderService = new StripeBase( + fakeContainer, { api_key: "test", payment_description: "test options description" }) - carts.frCart.customer_id = "" - carts.frCart.context.payment_description = null - result = await localStripeProviderService.createPayment(carts.frCart) + const cart = carts.frCart + const context = { + cart, + amount: cart.total, + currency_code: cart.region?.currency_code, + } + Object.assign(context, cart) + + context.cart.context.payment_description = null + + result = await localStripeProviderService.createPayment(context) expect(result).toEqual({ - id: "pi_lebron", - customer: "cus_lebron", - amount: 100, - description: "test options description", + session_data: { + id: "pi_lebron", + customer: "cus_lebron", + description: "test options description", + amount: 100, + }, + update_requests: { + customer_metadata: { + stripe_id: "cus_lebron" + } + } }) }) }) @@ -110,18 +108,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - { - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.retrievePayment({ + result = await stripeBase.retrievePayment({ payment_method: { data: { id: "pi_lebron", @@ -142,18 +136,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - { - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.updatePayment( + result = await stripeBase.updatePayment( { id: "pi_lebron", amount: 800, @@ -177,18 +167,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - { - customerService: CustomerServiceMock, - regionService: RegionServiceMock, - totalsService: TotalsServiceMock, - }, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.updatePaymentIntentCustomer( + result = await stripeBase.updatePaymentIntentCustomer( "pi_lebron", "cus_lebron_2" ) @@ -207,14 +193,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - {}, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.capturePayment({ + result = await stripeBase.capturePayment({ data: { id: "pi_lebron", customer: "cus_lebron", @@ -237,14 +223,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - {}, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.refundPayment( + result = await stripeBase.refundPayment( { data: { id: "re_123", @@ -271,14 +257,14 @@ describe("StripeProviderService", () => { let result beforeAll(async () => { jest.clearAllMocks() - const stripeProviderService = new StripeProviderService( - {}, + const stripeBase = new StripeBase( + fakeContainer, { api_key: "test", } ) - result = await stripeProviderService.cancelPayment({ + result = await stripeBase.cancelPayment({ data: { id: "pi_lebron", customer: "cus_lebron", diff --git a/packages/medusa-payment-stripe/src/helpers/stripe-base.js b/packages/medusa-payment-stripe/src/helpers/stripe-base.js index c5e49b4333..ac3194cc01 100644 --- a/packages/medusa-payment-stripe/src/helpers/stripe-base.js +++ b/packages/medusa-payment-stripe/src/helpers/stripe-base.js @@ -1,29 +1,12 @@ -import { AbstractPaymentService, PaymentSessionData } from "@medusajs/medusa" +import { AbstractPaymentService } from "@medusajs/medusa" import Stripe from "stripe" +import { PaymentSessionStatus } from "@medusajs/medusa/dist"; class StripeBase extends AbstractPaymentService { static identifier = null - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) /** * Required Stripe options: @@ -38,21 +21,6 @@ class StripeBase extends AbstractPaymentService { /** @private @const {Stripe} */ this.stripe_ = Stripe(options.api_key) - - /** @private @const {CustomerService} */ - this.stripeProviderService_ = stripeProviderService - - /** @private @const {CustomerService} */ - this.customerService_ = customerService - - /** @private @const {RegionService} */ - this.regionService_ = regionService - - /** @private @const {TotalsService} */ - this.totalsService_ = totalsService - - /** @private @const {EntityManager} */ - this.manager_ = manager } getPaymentIntentOptions() { @@ -74,22 +42,48 @@ class StripeBase extends AbstractPaymentService { return options } - /** - * Fetches Stripe payment intent. Check its status and returns the - * corresponding Medusa status. - * @param {PaymentSessionData} paymentSessionData - payment method data from cart - * @return {Promise} the status of the payment intent + /** + * Get payment session status + * statuses. + * @param {PaymentSessionData} paymentData - the data stored with the payment session + * @return {Promise} the status of the order */ - async getStatus(paymentSessionData) { - return await this.stripeProviderService_.getStatus(paymentSessionData) + async getStatus(paymentData) { + const { id } = paymentData + const paymentIntent = await this.stripe_.paymentIntents.retrieve(id) + + switch (paymentIntent.status) { + case "requires_payment_method": + case "requires_confirmation": + case "processing": + return PaymentSessionStatus.PENDING + case "requires_action": + return PaymentSessionStatus.REQUIRES_MORE + case "canceled": + return PaymentSessionStatus.CANCELED + case "requires_capture": + case "succeeded": + return PaymentSessionStatus.AUTHORIZED + default: + return PaymentSessionStatus.PENDING + } } /** * Fetches a customers saved payment methods if registered in Stripe. - * @param {object} customer - customer to fetch saved cards for + * @param {Customer} customer - customer to fetch saved cards for * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { + if (customer.metadata && customer.metadata.stripe_id) { + const methods = await this.stripe_.paymentMethods.list({ + customer: customer.metadata.stripe_id, + type: "card", + }) + + return methods.data + } + return [] } @@ -99,49 +93,68 @@ class StripeBase extends AbstractPaymentService { * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { - return await this.stripeProviderService_.retrieveCustomer(customerId) - } - - /** - * Creates a Stripe customer using a Medusa customer. - * @param {object} customer - Customer data from Medusa - * @return {Promise} Stripe customer - */ - async createCustomer(customer) { - return await this.stripeProviderService_ - .withTransaction(this.manager_) - .createCustomer(customer) + if (!customerId) { + return + } + return await this.stripe_.customers.retrieve(customerId) } /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {Cart} cart - cart to create a payment for - * @return {Promise} Stripe payment intent + * @param {Cart & PaymentContext} context - context to use to create a payment for + * @return {Promise} Stripe payment intent */ - async createPayment(cart) { + async createPayment(context) { const intentRequestData = this.getPaymentIntentOptions() + const { id: cart_id, email, context: cart_context, currency_code, amount, resource_id, customer } = context - return await this.stripeProviderService_ - .withTransaction(this.manager_) - .createPayment(cart, intentRequestData) - } + const intentRequest = { + description: + cart_context.payment_description ?? + this.options_?.payment_description, + amount: Math.round(amount), + currency: currency_code, + metadata: { cart_id, resource_id }, + capture_method: this.options_.capture ? "automatic" : "manual", + ...intentRequestData, + } - async createPaymentNew(paymentInput) { - const intentRequestData = this.getPaymentIntentOptions() + if (this.options_?.automatic_payment_methods) { + intentRequest.automatic_payment_methods = { enabled: true } + } - return await this.stripeProviderService_ - .withTransaction(this.manager_) - .createPaymentNew(paymentInput, intentRequestData) + if (customer?.metadata?.stripe_id) { + intentRequest.customer = customer?.metadata?.stripe_id + } else { + const stripeCustomer = await this.stripe_.customers.create({ + email, + }) + + intentRequest.customer = stripeCustomer.id + } + + const session_data = await this.stripe_.paymentIntents.create( + intentRequest + ) + + return { + session_data, + update_requests: { + customer_metadata: { + stripe_id: intentRequest.customer + } + } + } } /** * Retrieves Stripe payment intent. - * @param {PaymentData} paymentData - the data of the payment to retrieve + * @param {PaymentData} data - the data of the payment to retrieve * @return {Promise} Stripe payment intent */ - async retrievePayment(paymentData) { - return await this.stripeProviderService_.retrievePayment(paymentData) + async retrievePayment(data) { + return await this.stripe_.paymentIntents.retrieve(data.id) } /** @@ -150,67 +163,73 @@ class StripeBase extends AbstractPaymentService { * @return {Promise} Stripe payment intent */ async getPaymentData(paymentSession) { - return await this.stripeProviderService_.getPaymentData(paymentSession) + return await this.stripe_.paymentIntents.retrieve(paymentSession.data.id) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. * @param {PaymentSession} paymentSession - payment session data - * @param {object} context - properties relevant to current context - * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status + * @param {Data} context - properties relevant to current context + * @return {Promise<{ data: PaymentSessionData; status: PaymentSessionStatus }>} result with data and status */ async authorizePayment(paymentSession, context = {}) { - return await this.stripeProviderService_.authorizePayment( - paymentSession, - context - ) + const stat = await this.getStatus(paymentSession.data) + return { data: paymentSession.data, status: stat } } - async updatePaymentData(paymentSessionData, data) { - return await this.stripeProviderService_.updatePaymentData( - paymentSessionData, - data - ) + async updatePaymentData(sessionData, update) { + return await this.stripe_.paymentIntents.update(sessionData.id, { + ...update.data, + }) } /** * Updates Stripe payment intent. * @param {PaymentSessionData} paymentSessionData - payment session data. - * @param {Cart} cart + * @param {Cart & PaymentContext} context * @return {Promise} Stripe payment intent */ - async updatePayment(paymentSessionData, cart) { - const intentRequestData = this.getPaymentIntentOptions() + async updatePayment(paymentSessionData, context) { + const { amount, customer } = context + const stripeId = customer?.metadata?.stripe_id || undefined - return await this.stripeProviderService_ - .withTransaction(this.manager_) - .updatePayment(paymentSessionData, cart, intentRequestData) + if (stripeId !== paymentSessionData.customer) { + return await this.createPayment(context) + } else { + if ( + amount && + paymentSessionData.amount === Math.round(amount) + ) { + return paymentSessionData + } + + return await this.stripe_.paymentIntents.update(paymentSessionData.id, { + amount: Math.round(amount), + }) + } } - async updatePaymentNew(paymentSessionData, paymentInput) { - const intentRequestData = this.getPaymentIntentOptions() - - return await this.stripeProviderService_ - .withTransaction(this.manager_) - .updatePaymentNew(paymentSessionData, paymentInput, intentRequestData) - } - - async deletePayment(paymentSession) { - return await this.stripeProviderService_.deletePayment(paymentSession) + async deletePayment(payment) { + const { id } = payment.data + return this.stripe_.paymentIntents.cancel(id).catch((err) => { + if (err.statusCode === 400) { + return + } + throw err + }) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update - * @param {string} customerId - id of new Stripe customer + * @param {string} customerId - id of \ Stripe customer * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { - return await this.stripeProviderService_.updatePaymentIntentCustomer( - paymentIntentId, - customerId - ) + return await this.stripe_.paymentIntents.update(paymentIntentId, { + customer: customerId, + }) } /** @@ -219,7 +238,18 @@ class StripeBase extends AbstractPaymentService { * @return {Promise} Stripe payment intent */ async capturePayment(payment) { - return await this.stripeProviderService_.capturePayment(payment) + const { id } = payment.data + try { + const intent = await this.stripe_.paymentIntents.capture(id) + return intent + } catch (error) { + if (error.code === "payment_intent_unexpected_state") { + if (error.payment_intent.status === "succeeded") { + return error.payment_intent + } + } + throw error + } } /** @@ -228,11 +258,14 @@ class StripeBase extends AbstractPaymentService { * @param {number} refundAmount - amount to refund * @return {Promise} refunded payment intent */ - async refundPayment(payment, refundAmount) { - return await this.stripeProviderService_.refundPayment( - payment, - refundAmount - ) + async refundPayment(payment, amountToRefund) { + const { id } = payment.data + await this.stripe_.refunds.create({ + amount: Math.round(amountToRefund), + payment_intent: id, + }) + + return payment.data } /** @@ -241,7 +274,31 @@ class StripeBase extends AbstractPaymentService { * @return {Promise} canceled payment intent */ async cancelPayment(payment) { - return await this.stripeProviderService_.cancelPayment(payment) + const { id } = payment.data + try { + return await this.stripe_.paymentIntents.cancel(id) + } catch (error) { + if (error.payment_intent.status === "canceled") { + return error.payment_intent + } + + throw error + } + } + + /** + * Constructs Stripe Webhook event + * @param {object} data - the data of the webhook request: req.body + * @param {object} signature - the Stripe signature on the event, that + * ensures integrity of the webhook event + * @return {object} Stripe Webhook event + */ + constructWebhookEvent(data, signature) { + return this.stripe_.webhooks.constructEvent( + data, + signature, + this.options_.webhook_secret + ) } } diff --git a/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js b/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js deleted file mode 100644 index e49467719e..0000000000 --- a/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js +++ /dev/null @@ -1,55 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const StripeProviderServiceMock = { - withTransaction: function () { - return this - }, - retrievePayment: jest.fn().mockImplementation((payData) => { - if (payData.id === "pi_123456789") { - return Promise.resolve({ - id: "pi", - customer: "cus_123456789", - }) - } - if (payData.id === "pi_no") { - return Promise.resolve({ - id: "pi_no", - }) - } - return Promise.resolve(undefined) - }), - cancelPayment: jest.fn().mockImplementation((cart) => { - return Promise.resolve() - }), - updatePaymentIntentCustomer: jest.fn().mockImplementation((cart) => { - return Promise.resolve() - }), - retrieveCustomer: jest.fn().mockImplementation((customerId) => { - if (customerId === "cus_123456789_new") { - return Promise.resolve({ - id: "cus_123456789_new", - }) - } - return Promise.resolve(undefined) - }), - createCustomer: jest.fn().mockImplementation((customer) => { - if (customer._id === IdMap.getId("vvd")) { - return Promise.resolve({ - id: "cus_123456789_new_vvd", - }) - } - return Promise.resolve(undefined) - }), - createPayment: jest.fn().mockImplementation((cart) => { - return Promise.resolve({ - id: "pi_new", - customer: "cus_123456789_new", - }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return StripeProviderServiceMock -}) - -export default mock diff --git a/packages/medusa-payment-stripe/src/services/stripe-bancontact.js b/packages/medusa-payment-stripe/src/services/stripe-bancontact.js index a92ace64df..a12f9d5251 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-bancontact.js +++ b/packages/medusa-payment-stripe/src/services/stripe-bancontact.js @@ -3,26 +3,8 @@ import StripeBase from "../helpers/stripe-base" class BancontactProviderService extends StripeBase { static identifier = "stripe-bancontact" - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) } get paymentIntentOptions() { diff --git a/packages/medusa-payment-stripe/src/services/stripe-blik.js b/packages/medusa-payment-stripe/src/services/stripe-blik.js index 52f4c215c6..6e18a17fcc 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-blik.js +++ b/packages/medusa-payment-stripe/src/services/stripe-blik.js @@ -3,26 +3,8 @@ import StripeBase from "../helpers/stripe-base" class BlikProviderService extends StripeBase { static identifier = "stripe-blik" - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) } get paymentIntentOptions() { diff --git a/packages/medusa-payment-stripe/src/services/stripe-giropay.js b/packages/medusa-payment-stripe/src/services/stripe-giropay.js index 8b04bde24a..94b19415f0 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-giropay.js +++ b/packages/medusa-payment-stripe/src/services/stripe-giropay.js @@ -3,26 +3,8 @@ import StripeBase from "../helpers/stripe-base" class GiropayProviderService extends StripeBase { static identifier = "stripe-giropay" - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) } get paymentIntentOptions() { diff --git a/packages/medusa-payment-stripe/src/services/stripe-ideal.js b/packages/medusa-payment-stripe/src/services/stripe-ideal.js index b230a78460..6d20df143c 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-ideal.js +++ b/packages/medusa-payment-stripe/src/services/stripe-ideal.js @@ -3,26 +3,8 @@ import StripeBase from "../helpers/stripe-base" class IdealProviderService extends StripeBase { static identifier = "stripe-ideal" - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) } get paymentIntentOptions() { diff --git a/packages/medusa-payment-stripe/src/services/stripe-provider.js b/packages/medusa-payment-stripe/src/services/stripe-provider.js index 47ea452408..ac2f47a232 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-provider.js +++ b/packages/medusa-payment-stripe/src/services/stripe-provider.js @@ -1,424 +1,14 @@ -import { - AbstractPaymentService, - PaymentSessionData, - PaymentSessionStatus, -} from "@medusajs/medusa" -import Stripe from "stripe" +import StripeBase from "../helpers/stripe-base"; -class StripeProviderService extends AbstractPaymentService { +class StripeProviderService extends StripeBase { static identifier = "stripe" - constructor( - { customerService, totalsService, regionService, manager }, - options - ) { - super({ customerService, totalsService, regionService, manager }, options) - - /** - * Required Stripe options: - * { - * api_key: "stripe_secret_key", REQUIRED - * webhook_secret: "stripe_webhook_secret", REQUIRED - * // Use this flag to capture payment immediately (default is false) - * capture: true - * } - */ - this.options_ = options - - /** @private @const {Stripe} */ - this.stripe_ = Stripe(options.api_key) - - /** @private @const {CustomerService} */ - this.customerService_ = customerService - - /** @private @const {RegionService} */ - this.regionService_ = regionService - - /** @private @const {TotalsService} */ - this.totalsService_ = totalsService - - /** @private @const {EntityManager} */ - this.manager_ = manager + constructor(_, options) { + super(_, options) } - /** - * Get payment session status - * statuses. - * @param {PaymentSessionData} paymentData - the data stored with the payment session - * @return {Promise} the status of the order - */ - async getStatus(paymentData) { - const { id } = paymentData - const paymentIntent = await this.stripe_.paymentIntents.retrieve(id) - - switch (paymentIntent.status) { - case "requires_payment_method": - case "requires_confirmation": - case "processing": - return PaymentSessionStatus.PENDING - case "requires_action": - return PaymentSessionStatus.REQUIRES_MORE - case "canceled": - return PaymentSessionStatus.CANCELED - case "requires_capture": - case "succeeded": - return PaymentSessionStatus.AUTHORIZED - default: - return PaymentSessionStatus.PENDING - } - } - - /** - * Fetches a customers saved payment methods if registered in Stripe. - * @param {Customer} customer - customer to fetch saved cards for - * @return {Promise} saved payments methods - */ - async retrieveSavedMethods(customer) { - if (customer.metadata && customer.metadata.stripe_id) { - const methods = await this.stripe_.paymentMethods.list({ - customer: customer.metadata.stripe_id, - type: "card", - }) - - return methods.data - } - - return [] - } - - /** - * Fetches a Stripe customer - * @param {string} customerId - Stripe customer id - * @return {Promise} Stripe customer - */ - async retrieveCustomer(customerId) { - if (!customerId) { - return Promise.resolve() - } - return this.stripe_.customers.retrieve(customerId) - } - - /** - * Creates a Stripe customer using a Medusa customer. - * @param {object} customer - Customer data from Medusa - * @return {Promise} Stripe customer - */ - async createCustomer(customer) { - try { - const stripeCustomer = await this.stripe_.customers.create({ - email: customer.email, - }) - - if (customer.id) { - await this.customerService_ - .withTransaction(this.manager_) - .update(customer.id, { - metadata: { stripe_id: stripeCustomer.id }, - }) - } - - return stripeCustomer - } catch (error) { - throw error - } - } - - /** - * Creates a Stripe payment intent. - * If customer is not registered in Stripe, we do so. - * @param {Cart} cart - cart to create a payment for - * @param intentRequestData - * @return {Promise} Stripe payment intent - */ - async createPayment(cart, intentRequestData = {}) { - const { customer_id, region_id, email } = cart - const { currency_code } = await this.regionService_ - .withTransaction(this.manager_) - .retrieve(region_id) - - const amount = cart.total - - const intentRequest = { - description: - cart?.context?.payment_description ?? - this.options_?.payment_description, - amount: Math.round(amount), - currency: currency_code, - metadata: { cart_id: `${cart.id}` }, - capture_method: this.options_.capture ? "automatic" : "manual", - ...intentRequestData, - } - - if (this.options_?.automatic_payment_methods) { - intentRequest.automatic_payment_methods = { enabled: true } - } - - if (customer_id) { - const customer = await this.customerService_ - .withTransaction(this.manager_) - .retrieve(customer_id) - - if (customer.metadata?.stripe_id) { - intentRequest.customer = customer.metadata.stripe_id - } else { - const stripeCustomer = await this.createCustomer({ - email, - id: customer_id, - }) - - intentRequest.customer = stripeCustomer.id - } - } else { - const stripeCustomer = await this.createCustomer({ - email, - }) - - intentRequest.customer = stripeCustomer.id - } - - return await this.stripe_.paymentIntents.create(intentRequest) - } - - async createPaymentNew(paymentInput, intentRequestData = {}) { - const { customer, currency_code, amount, resource_id, cart } = paymentInput - const { id: customer_id, email } = customer ?? {} - - const intentRequest = { - description: - cart?.context?.payment_description ?? - this.options_?.payment_description, - amount: Math.round(amount), - currency: currency_code, - metadata: { resource_id }, - capture_method: this.options_.capture ? "automatic" : "manual", - ...intentRequestData, - } - - if (customer_id) { - if (customer.metadata?.stripe_id) { - intentRequest.customer = customer.metadata.stripe_id - } else { - const stripeCustomer = await this.createCustomer({ - email, - id: customer_id, - }) - - intentRequest.customer = stripeCustomer.id - } - } else if (email) { - const stripeCustomer = await this.createCustomer({ - email, - }) - - intentRequest.customer = stripeCustomer.id - } - - return await this.stripe_.paymentIntents.create(intentRequest) - } - - /** - * Retrieves Stripe payment intent. - * @param {PaymentData} paymentData - the data of the payment to retrieve - * @return {Promise} Stripe payment intent - */ - async retrievePayment(data) { - try { - return await this.stripe_.paymentIntents.retrieve(data.id) - } catch (error) { - throw error - } - } - - /** - * Gets a Stripe payment intent and returns it. - * @param {PaymentSession} paymentSession - the data of the payment to retrieve - * @return {Promise} Stripe payment intent - */ - async getPaymentData(paymentSession) { - try { - return await this.stripe_.paymentIntents.retrieve(paymentSession.data.id) - } catch (error) { - throw error - } - } - - /** - * Authorizes Stripe payment intent by simply returning - * the status for the payment intent in use. - * @param {PaymentSession} paymentSession - payment session data - * @param {Data} context - properties relevant to current context - * @return {Promise<{ data: PaymentSessionData; status: PaymentSessionStatus }>} result with data and status - */ - async authorizePayment(paymentSession, context = {}) { - const stat = await this.getStatus(paymentSession.data) - try { - return { data: paymentSession.data, status: stat } - } catch (error) { - throw error - } - } - - async updatePaymentData(sessionData, update) { - try { - return await this.stripe_.paymentIntents.update(sessionData.id, { - ...update.data, - }) - } catch (error) { - throw error - } - } - - /** - * Updates Stripe payment intent. - * @param {PaymentSessionData} paymentSessionData - payment session data. - * @param {Cart} cart - * @param intentRequestData - * @return {Promise} Stripe payment intent - */ - async updatePayment(paymentSessionData, cart, intentRequestData) { - try { - const stripeId = cart.customer?.metadata?.stripe_id || undefined - - if (stripeId !== paymentSessionData.customer) { - return await this.createPayment(cart, intentRequestData) - } else { - if ( - cart.total && - paymentSessionData.amount === Math.round(cart.total) - ) { - return paymentSessionData - } - - return await this.stripe_.paymentIntents.update(paymentSessionData.id, { - amount: Math.round(cart.total), - }) - } - } catch (error) { - throw error - } - } - - async updatePaymentNew(paymentSessionData, paymentInput, intentRequestData) { - try { - const stripeId = paymentInput.customer?.metadata?.stripe_id - - if (stripeId !== paymentSessionData.customer) { - return await this.createPaymentNew(paymentInput, intentRequestData) - } else { - if (paymentSessionData.amount === Math.round(paymentInput.amount)) { - return paymentSessionData - } - - return await this.stripe_.paymentIntents.update(paymentSessionData.id, { - amount: Math.round(paymentInput.amount), - }) - } - } catch (error) { - throw error - } - } - - async deletePayment(payment) { - try { - const { id } = payment.data - return this.stripe_.paymentIntents.cancel(id).catch((err) => { - if (err.statusCode === 400) { - return - } - throw err - }) - } catch (error) { - throw error - } - } - - /** - * Updates customer of Stripe payment intent. - * @param {string} paymentIntentId - id of payment intent to update - * @param {string} customerId - id of new Stripe customer - * @return {object} Stripe payment intent - */ - async updatePaymentIntentCustomer(paymentIntentId, customerId) { - try { - return await this.stripe_.paymentIntents.update(paymentIntentId, { - customer: customerId, - }) - } catch (error) { - throw error - } - } - - /** - * Captures payment for Stripe payment intent. - * @param {Payment} payment - payment method data from cart - * @return {Promise} Stripe payment intent - */ - async capturePayment(payment) { - const { id } = payment.data - try { - const intent = await this.stripe_.paymentIntents.capture(id) - return intent - } catch (error) { - if (error.code === "payment_intent_unexpected_state") { - if (error.payment_intent.status === "succeeded") { - return error.payment_intent - } - } - throw error - } - } - - /** - * Refunds payment for Stripe payment intent. - * @param {Payment} payment - payment method data from cart - * @param {number} refundAmount - amount to refund - * @return {Promise} refunded payment intent - */ - async refundPayment(payment, amountToRefund) { - const { id } = payment.data - try { - await this.stripe_.refunds.create({ - amount: Math.round(amountToRefund), - payment_intent: id, - }) - - return payment.data - } catch (error) { - throw error - } - } - - /** - * Cancels payment for Stripe payment intent. - * @param {Payment} payment - payment method data from cart - * @return {Promise} canceled payment intent - */ - async cancelPayment(payment) { - const { id } = payment.data - try { - return await this.stripe_.paymentIntents.cancel(id) - } catch (error) { - if (error.payment_intent.status === "canceled") { - return error.payment_intent - } - - throw error - } - } - - /** - * Constructs Stripe Webhook event - * @param {object} data - the data of the webhook request: req.body - * @param {object} signature - the Stripe signature on the event, that - * ensures integrity of the webhook event - * @return {object} Stripe Webhook event - */ - constructWebhookEvent(data, signature) { - return this.stripe_.webhooks.constructEvent( - data, - signature, - this.options_.webhook_secret - ) + get paymentIntentOptions() { + return {} } } diff --git a/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js b/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js index 9e10c43ac4..236d8c38b0 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js +++ b/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js @@ -3,26 +3,8 @@ import StripeBase from "../helpers/stripe-base" class Przelewy24ProviderService extends StripeBase { static identifier = "stripe-przelewy24" - constructor( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) { - super( - { - stripeProviderService, - customerService, - totalsService, - regionService, - manager, - }, - options - ) + constructor(_, options) { + super(_, options) } get paymentIntentOptions() { diff --git a/packages/medusa-payment-stripe/src/subscribers/cart.js b/packages/medusa-payment-stripe/src/subscribers/cart.js deleted file mode 100644 index 7def274536..0000000000 --- a/packages/medusa-payment-stripe/src/subscribers/cart.js +++ /dev/null @@ -1,60 +0,0 @@ -class CartSubscriber { - constructor({ - manager, - cartService, - paymentProviderService, - eventBusService, - }) { - this.cartService_ = cartService - this.paymentProviderService_ = paymentProviderService - this.eventBus_ = eventBusService - this.manager_ = manager - - this.eventBus_.subscribe("cart.customer_updated", async (cart) => { - await this.onCustomerUpdated(cart) - }) - } - - async onCustomerUpdated(cartId) { - await this.manager_.transaction(async (transactionManager) => { - const cart = await this.cartService_ - .withTransaction(transactionManager) - .retrieve(cartId, { - select: [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "gift_card_total", - "total", - ], - relations: [ - "billing_address", - "shipping_address", - "region", - "region.payment_providers", - "items", - "items.adjustments", - "payment_sessions", - "customer", - ], - }) - - if (!cart.payment_sessions?.length) { - return Promise.resolve() - } - - const session = cart.payment_sessions.find( - (ps) => ps.provider_id === "stripe" - ) - - if (session) { - return await this.paymentProviderService_ - .withTransaction(transactionManager) - .updateSession(session, cart) - } - }) - } -} - -export default CartSubscriber diff --git a/packages/medusa-plugin-economic/utils/eu-countries.js b/packages/medusa-plugin-economic/utils/eu-countries.js old mode 100755 new mode 100644 diff --git a/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts b/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts index 0c4ebf329c..3461b71a03 100644 --- a/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts +++ b/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts @@ -6,7 +6,7 @@ import { DateComparisonOperator } from "../../../../types/common" import { IsType } from "../../../../utils/validators/is-type" import { Request } from "express" import { pickBy } from "lodash" -import { isDefined } from "../../../../utils" +import { isDefined } from "medusa-core-utils" /** * @oas [get] /batch-jobs diff --git a/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts b/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts index 39c8e72d79..626edd548b 100644 --- a/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts +++ b/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts @@ -4,7 +4,7 @@ import { GiftCardService } from "../../../../services" import { Type } from "class-transformer" import { pickBy } from "lodash" import { validator } from "../../../../utils/validator" -import { isDefined } from "../../../../utils" +import { isDefined } from "medusa-core-utils" /** * @oas [get] /gift-cards diff --git a/packages/medusa/src/api/routes/admin/orders/request-return.ts b/packages/medusa/src/api/routes/admin/orders/request-return.ts index 42e9c9fa2d..36ea080e74 100644 --- a/packages/medusa/src/api/routes/admin/orders/request-return.ts +++ b/packages/medusa/src/api/routes/admin/orders/request-return.ts @@ -14,11 +14,10 @@ import { } from "../../../../services" import { Type } from "class-transformer" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { Order, Return } from "../../../../models" import { OrdersReturnItem } from "../../../../types/orders" -import { isDefined } from "../../../../utils" import { validator } from "../../../../utils/validator" /** diff --git a/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts b/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts index 0e0a0c79cd..3980af7875 100644 --- a/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts +++ b/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts @@ -17,7 +17,7 @@ import { ProductStatus } from "../../../../models" import { Request } from "express" import { Type } from "class-transformer" import { pickBy } from "lodash" -import { isDefined } from "../../../../utils" +import { isDefined } from "medusa-core-utils" /** * @oas [get] /price-lists/{id}/products diff --git a/packages/medusa/src/api/routes/admin/returns/receive-return.ts b/packages/medusa/src/api/routes/admin/returns/receive-return.ts index 3f61842eb2..09084a73bd 100644 --- a/packages/medusa/src/api/routes/admin/returns/receive-return.ts +++ b/packages/medusa/src/api/routes/admin/returns/receive-return.ts @@ -10,7 +10,7 @@ import { OrderService, ReturnService, SwapService } from "../../../../services" import { EntityManager } from "typeorm" import { Type } from "class-transformer" import { validator } from "../../../../utils/validator" -import { isDefined } from "../../../../utils" +import { isDefined } from "medusa-core-utils" /** * @oas [post] /returns/{id}/receive diff --git a/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts index 4c2e642860..f3b435d067 100644 --- a/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts +++ b/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts @@ -3,12 +3,11 @@ import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" import { EntityManager } from "typeorm" import { IsType } from "../../../../utils/validators/is-type" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { TaxRate } from "../../../.." import { TaxRateService } from "../../../../services" import { omit } from "lodash" import { validator } from "../../../../utils/validator" -import { isDefined } from "../../../../utils" /** * @oas [post] /tax-rates diff --git a/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts index 984dbb6e05..be11f888ce 100644 --- a/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts +++ b/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts @@ -7,7 +7,7 @@ import { TaxRate } from "../../../.." import { TaxRateService } from "../../../../services" import { omit } from "lodash" import { validator } from "../../../../utils/validator" -import { isDefined } from "../../../../utils" +import { isDefined } from "medusa-core-utils" /** * @oas [post] /tax-rates/{id} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts b/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts index 36e1952631..55a530c2f0 100644 --- a/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts +++ b/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts @@ -2,7 +2,7 @@ import { pick } from "lodash" import { defaultAdminTaxRatesFields, defaultAdminTaxRatesRelations } from "../" import { TaxRate } from "../../../../.." import { FindConfig } from "../../../../../types/common" -import { isDefined } from "../../../../../utils" +import { isDefined } from "medusa-core-utils" export function pickByConfig( obj: T | T[], diff --git a/packages/medusa/src/api/routes/store/carts/create-cart.ts b/packages/medusa/src/api/routes/store/carts/create-cart.ts index cbeb8a26f7..383f5dffc0 100644 --- a/packages/medusa/src/api/routes/store/carts/create-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/create-cart.ts @@ -1,5 +1,5 @@ import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import reqIp from "request-ip" import { Type } from "class-transformer" import { @@ -22,7 +22,6 @@ import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators import { FlagRouter } from "../../../../utils/flag-router" import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" import { CartCreateProps } from "../../../../types/cart" -import { isDefined } from "../../../../utils" import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys" /** diff --git a/packages/medusa/src/api/routes/store/products/list-products.ts b/packages/medusa/src/api/routes/store/products/list-products.ts index 393e81f397..2ea7ad9b60 100644 --- a/packages/medusa/src/api/routes/store/products/list-products.ts +++ b/packages/medusa/src/api/routes/store/products/list-products.ts @@ -13,14 +13,13 @@ import { ProductService, RegionService, } from "../../../../services" - +import { isDefined } from "medusa-core-utils" import { defaultStoreProductsRelations } from "." import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" import { Product } from "../../../../models" import PricingService from "../../../../services/pricing" import { DateComparisonOperator } from "../../../../types/common" import { PriceSelectionParams } from "../../../../types/price-selection" -import { isDefined } from "../../../../utils" import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" import { validator } from "../../../../utils/validator" import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" diff --git a/packages/medusa/src/controllers/customers/list-customers.ts b/packages/medusa/src/controllers/customers/list-customers.ts index f787086f81..0d8660fdb8 100644 --- a/packages/medusa/src/controllers/customers/list-customers.ts +++ b/packages/medusa/src/controllers/customers/list-customers.ts @@ -5,7 +5,7 @@ import { CustomerService } from "../../services" import { FindConfig } from "../../types/common" import { validator } from "../../utils/validator" import { Customer } from "../../models/customer" -import { isDefined } from "../../utils" +import { isDefined } from "medusa-core-utils" const listAndCount = async ( scope, diff --git a/packages/medusa/src/interfaces/payment-service.ts b/packages/medusa/src/interfaces/payment-service.ts index 6094ef8a2a..e4141ac8f6 100644 --- a/packages/medusa/src/interfaces/payment-service.ts +++ b/packages/medusa/src/interfaces/payment-service.ts @@ -1,18 +1,38 @@ import { TransactionBaseService } from "./transaction-base-service" import { + Address, Cart, Customer, Payment, PaymentSession, PaymentSessionStatus, + ShippingMethod, } from "../models" import { PaymentService } from "medusa-interfaces" -import { PaymentProviderDataInput } from "../types/payment-collection" export type Data = Record export type PaymentData = Data export type PaymentSessionData = Data +export type PaymentContext = { + cart: { + context: Record + id: string + email: string + shipping_address: Address | null + shipping_methods: ShippingMethod[] + } + currency_code: string + amount: number + resource_id?: string + customer?: Customer +} + +export type PaymentSessionResponse = { + update_requests: { customer_metadata: Record } + session_data: Record +} + export interface PaymentService extends TransactionBaseService { getIdentifier(): string @@ -23,6 +43,16 @@ export interface PaymentService extends TransactionBaseService { data: Data ): Promise + /** + * @param context The type of this argument is meant to be temporary and once the previous method signature + * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext + */ + createPayment(context: Cart & PaymentContext): Promise + + /** + * @deprecated use createPayment(context: Cart & PaymentContext): Promise instead + * @param cart + */ createPayment(cart: Cart): Promise retrievePayment(paymentData: PaymentData): Promise @@ -76,23 +106,42 @@ export abstract class AbstractPaymentService data: Data ): Promise + /** + * @param context The type of this argument is meant to be temporary and once the previous method signature + * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext + */ + public abstract createPayment( + context: Cart & PaymentContext + ): Promise + + /** + * @deprecated use createPayment(context: Cart & PaymentContext): Promise instead + * @param cart + */ public abstract createPayment(cart: Cart): Promise - public abstract createPaymentNew( - paymentInput: PaymentProviderDataInput - ): Promise public abstract retrievePayment(paymentData: PaymentData): Promise + /** + * @param paymentSessionData + * @param context The type of this argument is meant to be temporary and once the previous method signature + * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext + */ + public abstract updatePayment( + paymentSessionData: PaymentSessionData, + context: Cart & PaymentContext + ): Promise + + /** + * @deprecated use updatePayment(paymentSessionData: PaymentSessionData, context: Cart & PaymentContext): Promise instead + * @param paymentSessionData + * @param cart + */ public abstract updatePayment( paymentSessionData: PaymentSessionData, cart: Cart ): Promise - public abstract updatePaymentNew( - paymentSessionData: PaymentSessionData, - paymentInput: PaymentProviderDataInput - ): Promise - public abstract authorizePayment( paymentSession: PaymentSession, context: Data diff --git a/packages/medusa/src/loaders/feature-flags/index.ts b/packages/medusa/src/loaders/feature-flags/index.ts index 1bb6abffda..31f38fad3a 100644 --- a/packages/medusa/src/loaders/feature-flags/index.ts +++ b/packages/medusa/src/loaders/feature-flags/index.ts @@ -4,7 +4,7 @@ import path from "path" import { trackFeatureFlag } from "medusa-telemetry" import { FlagSettings } from "../../types/feature-flags" import { Logger } from "../../types/global" -import { isDefined } from "../../utils" +import { isDefined } from "medusa-core-utils" import { FlagRouter } from "../../utils/flag-router" const isTruthy = (val: string | boolean | undefined): boolean => { diff --git a/packages/medusa/src/loaders/services.ts b/packages/medusa/src/loaders/services.ts index 67f297b26f..90a0d12792 100644 --- a/packages/medusa/src/loaders/services.ts +++ b/packages/medusa/src/loaders/services.ts @@ -2,7 +2,7 @@ import { asFunction } from "awilix" import glob from "glob" import path from "path" import { ConfigModule, MedusaContainer } from "../types/global" -import { isDefined } from "../utils" +import { isDefined } from "medusa-core-utils" import formatRegistrationName from "../utils/format-registration-name" type Options = { diff --git a/packages/medusa/src/loaders/strategies.ts b/packages/medusa/src/loaders/strategies.ts index e161b83de8..22808c3444 100644 --- a/packages/medusa/src/loaders/strategies.ts +++ b/packages/medusa/src/loaders/strategies.ts @@ -5,7 +5,7 @@ import { aliasTo, asFunction } from "awilix" import formatRegistrationName from "../utils/format-registration-name" import { isBatchJobStrategy } from "../interfaces" import { MedusaContainer } from "../types/global" -import { isDefined } from "../utils" +import { isDefined } from "medusa-core-utils" type LoaderOptions = { container: MedusaContainer diff --git a/packages/medusa/src/models/payment-session.ts b/packages/medusa/src/models/payment-session.ts index a5bcb429d1..ddfaa61b0c 100644 --- a/packages/medusa/src/models/payment-session.ts +++ b/packages/medusa/src/models/payment-session.ts @@ -1,12 +1,4 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Unique, -} from "typeorm" +import { BeforeInsert, Column, Entity, Index, JoinColumn, ManyToOne, Unique, } from "typeorm" import { BaseEntity } from "../interfaces" import { Cart } from "./cart" @@ -24,12 +16,13 @@ export enum PaymentSessionStatus { } @Unique("OneSelected", ["cart_id", "is_selected"]) +// TODO: This uniq constraint should be updated once the order edit flag is dropped and should add a where clause on cart_id is not null @Unique("UniqPaymentSessionCartIdProviderId", ["cart_id", "provider_id"]) @Entity() export class PaymentSession extends BaseEntity { @Index() @Column({ nullable: true }) - cart_id: string + cart_id: string | null @ManyToOne(() => Cart, (cart) => cart.payment_sessions) @JoinColumn({ name: "cart_id" }) diff --git a/packages/medusa/src/repositories/payment-collection.ts b/packages/medusa/src/repositories/payment-collection.ts index 382181f9dc..99a5190ef3 100644 --- a/packages/medusa/src/repositories/payment-collection.ts +++ b/packages/medusa/src/repositories/payment-collection.ts @@ -2,7 +2,6 @@ import { MedusaError } from "medusa-core-utils" import { PaymentCollection } from "./../models/payment-collection" import { EntityRepository, Repository } from "typeorm" import { FindConfig } from "../types/common" -import { PaymentSession } from "../models" @EntityRepository(PaymentCollection) // eslint-disable-next-line max-len @@ -61,12 +60,4 @@ export class PaymentCollectionRepository extends Repository { return paymentCollection[0] } - - async deleteMultiple(ids: string[]): Promise { - await this.createQueryBuilder() - .delete() - .from(PaymentSession) - .where("id IN (:...ids)", { ids }) - .execute() - } } diff --git a/packages/medusa/src/repositories/tax-rate.ts b/packages/medusa/src/repositories/tax-rate.ts index bd78337685..5b231555f8 100644 --- a/packages/medusa/src/repositories/tax-rate.ts +++ b/packages/medusa/src/repositories/tax-rate.ts @@ -1,22 +1,23 @@ import { unionBy } from "lodash" import { - In, - Not, DeleteResult, - SelectQueryBuilder, EntityRepository, FindManyOptions, FindOptionsUtils, + In, + Not, Repository, + SelectQueryBuilder, } from "typeorm" -import { TaxRate } from "../models/tax-rate" -import { ProductTaxRate } from "../models/product-tax-rate" -import { ProductTypeTaxRate } from "../models/product-type-tax-rate" -import { ShippingTaxRate } from "../models/shipping-tax-rate" -import { Product } from "../models/product" -import { ShippingMethod } from "../models/shipping-method" +import { + Product, + ProductTaxRate, + ProductTypeTaxRate, + ShippingTaxRate, + TaxRate, +} from "../models" import { TaxRateListByConfig } from "../types/tax-rate" -import { isDefined } from "../utils" +import { isDefined } from "medusa-core-utils" const resolveableFields = [ "product_count", diff --git a/packages/medusa/src/services/__fixtures__/payment-provider.ts b/packages/medusa/src/services/__fixtures__/payment-provider.ts new file mode 100644 index 0000000000..c33ff60d1e --- /dev/null +++ b/packages/medusa/src/services/__fixtures__/payment-provider.ts @@ -0,0 +1,18 @@ +import { asClass, asValue, createContainer } from "awilix" +import { MockManager, MockRepository } from "medusa-test-utils" +import PaymentProviderService from "../payment-provider"; +import { PaymentProviderServiceMock } from "../__mocks__/payment-provider"; +import { CustomerServiceMock } from "../__mocks__/customer"; +import { FlagRouter } from "../../utils/flag-router"; +import Logger from "../../loaders/logger"; + +export const defaultContainer = createContainer() +defaultContainer.register("paymentProviderService", asClass(PaymentProviderService)) +defaultContainer.register("manager", asValue(MockManager)) +defaultContainer.register("paymentSessionRepository", asValue(MockRepository())) +defaultContainer.register("paymentProviderRepository", asValue(PaymentProviderServiceMock)) +defaultContainer.register("paymentRepository", asValue(MockRepository())) +defaultContainer.register("refundRepository", asValue(MockRepository())) +defaultContainer.register("customerService", asValue(CustomerServiceMock)) +defaultContainer.register("featureFlagRouter", asValue(new FlagRouter({}))) +defaultContainer.register("logger", asValue(Logger)) diff --git a/packages/medusa/src/services/__mocks__/payment-provider.js b/packages/medusa/src/services/__mocks__/payment-provider.js index d32c1e3a31..8c2236a45b 100644 --- a/packages/medusa/src/services/__mocks__/payment-provider.js +++ b/packages/medusa/src/services/__mocks__/payment-provider.js @@ -1,3 +1,5 @@ +import { isString } from "../../utils"; + export const DefaultProviderMock = { getStatus: jest.fn().mockImplementation((data) => { if (data.money_id === "success") { @@ -28,12 +30,6 @@ export const PaymentProviderServiceMock = { return this }, updateSession: jest.fn().mockImplementation((session, cart) => { - return Promise.resolve({ - ...session.data, - id: `${session.data.id}_updated`, - }) - }), - updateSessionNew: jest.fn().mockImplementation((session, sessionInput) => { return Promise.resolve({ ...session, id: `${session.id}_updated`, @@ -45,16 +41,17 @@ export const PaymentProviderServiceMock = { registerInstalledProviders: jest.fn().mockImplementation(() => { return Promise.resolve() }), - createSession: jest.fn().mockImplementation((providerId, cart) => { - return Promise.resolve({ - id: `${providerId}_session`, - cartId: cart._id, - }) - }), - createSessionNew: jest.fn().mockImplementation((sessionInput) => { - return Promise.resolve({ - id: `${sessionInput.providerId}_session`, - }) + createSession: jest.fn().mockImplementation((providerIdOrSessionInput, cart) => { + if (isString(providerIdOrSessionInput)) { + return Promise.resolve({ + id: `${providerIdOrSessionInput}_session`, + cartId: cart._id, + }) + } else { + return Promise.resolve({ + id: `${providerIdOrSessionInput.providerId}_session`, + }) + } }), retrieveProvider: jest.fn().mockImplementation((providerId) => { if (providerId === "default_provider") { @@ -62,9 +59,9 @@ export const PaymentProviderServiceMock = { } throw new Error("Provider Not Found") }), - refreshSessionNew: jest.fn().mockImplementation((session, inputData) => { + refreshSession: jest.fn().mockImplementation((session, inputData) => { DefaultProviderMock.deletePayment() - PaymentProviderServiceMock.createSessionNew(inputData) + PaymentProviderServiceMock.createSession(inputData) return Promise.resolve({ ...session, id: `${session.id}_refreshed`, @@ -73,7 +70,7 @@ export const PaymentProviderServiceMock = { authorizePayment: jest .fn() .mockReturnValue(Promise.resolve({ status: "authorized" })), - createPaymentNew: jest.fn().mockImplementation((session, inputData) => { + createPayment: jest.fn().mockImplementation((session, inputData) => { Promise.resolve(inputData) }), } diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js index ba0ded1d45..007e88c7db 100644 --- a/packages/medusa/src/services/__tests__/cart.js +++ b/packages/medusa/src/services/__tests__/cart.js @@ -1528,12 +1528,22 @@ describe("CartService", () => { expect(paymentProviderService.createSession).toHaveBeenCalledTimes(2) expect(paymentProviderService.createSession).toHaveBeenCalledWith( - "provider_1", - cart1 + { + cart: cart1, + customer: cart1.customer, + amount: cart1.total, + currency_code: cart1.region.currency_code, + provider_id: "provider_1", + } ) expect(paymentProviderService.createSession).toHaveBeenCalledWith( - "provider_2", - cart1 + { + cart: cart1, + customer: cart1.customer, + amount: cart1.total, + currency_code: cart1.region.currency_code, + provider_id: "provider_2", + } ) }) diff --git a/packages/medusa/src/services/__tests__/payment-collection.ts b/packages/medusa/src/services/__tests__/payment-collection.ts index ad2de73bfb..9ec0cedf6f 100644 --- a/packages/medusa/src/services/__tests__/payment-collection.ts +++ b/packages/medusa/src/services/__tests__/payment-collection.ts @@ -1,21 +1,8 @@ import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { - CustomerService, - EventBusService, - PaymentCollectionService, - PaymentProviderService, - PaymentService, -} from "../index" -import { - PaymentCollectionStatus, - PaymentCollectionType, - PaymentCollection, -} from "../../models" +import { CustomerService, EventBusService, PaymentCollectionService, PaymentProviderService, } from "../index" +import { PaymentCollection, PaymentCollectionStatus, PaymentCollectionType, } from "../../models" import { EventBusServiceMock } from "../__mocks__/event-bus" -import { - DefaultProviderMock, - PaymentProviderServiceMock, -} from "../__mocks__/payment-provider" +import { DefaultProviderMock, PaymentProviderServiceMock, } from "../__mocks__/payment-provider" import { CustomerServiceMock } from "../__mocks__/customer" import { PaymentCollectionsSessionsBatchInput } from "../../types/payment-collection" @@ -395,7 +382,7 @@ describe("PaymentCollectionService", () => { `Cannot set payment sessions for a payment collection with status ${PaymentCollectionStatus.AUTHORIZED}` ) ) - expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) }) it("should ignore session if provider doesn't belong to the region", async () => { @@ -408,7 +395,7 @@ describe("PaymentCollectionService", () => { ) expect(multiRet).rejects.toThrow(`Payment provider not found`) - expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) }) it("should add a new session", async () => { @@ -420,7 +407,7 @@ describe("PaymentCollectionService", () => { "lebron" ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 1 ) expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) @@ -436,10 +423,10 @@ describe("PaymentCollectionService", () => { "lebron" ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 0 ) - expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes( 1 ) expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) @@ -459,13 +446,13 @@ describe("PaymentCollectionService", () => { IdMap.getId("lebron") ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 1 ) - expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes( 0 ) - expect(paymentCollectionRepository.deleteMultiple).toHaveBeenCalledTimes( + expect(paymentCollectionRepository.delete).toHaveBeenCalledTimes( 1 ) @@ -497,7 +484,7 @@ describe("PaymentCollectionService", () => { ) ) - expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) }) it("should throw error if amount is different than requested", async () => { @@ -514,7 +501,7 @@ describe("PaymentCollectionService", () => { "customer1" ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 0 ) expect(ret).rejects.toThrow( @@ -537,7 +524,7 @@ describe("PaymentCollectionService", () => { "customer1" ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 0 ) expect(multiRet).rejects.toThrow( @@ -565,7 +552,7 @@ describe("PaymentCollectionService", () => { expect(multiRet).rejects.toThrow( `The sum of sessions is not equal to 100 on Payment Collection` ) - expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) }) it("should add a new session and update existing one", async () => { @@ -586,10 +573,10 @@ describe("PaymentCollectionService", () => { "lebron" ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 1 ) - expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes( 1 ) expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) @@ -609,13 +596,13 @@ describe("PaymentCollectionService", () => { IdMap.getId("lebron") ) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 1 ) - expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes( 0 ) - expect(paymentCollectionRepository.deleteMultiple).toHaveBeenCalledTimes( + expect(paymentCollectionRepository.delete).toHaveBeenCalledTimes( 1 ) @@ -630,10 +617,10 @@ describe("PaymentCollectionService", () => { ) expect( - PaymentProviderServiceMock.refreshSessionNew + PaymentProviderServiceMock.refreshSession ).toHaveBeenCalledTimes(1) expect(DefaultProviderMock.deletePayment).toHaveBeenCalledTimes(1) - expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes( 1 ) }) @@ -650,9 +637,9 @@ describe("PaymentCollectionService", () => { "payCol_session-not-found" )} was not found` ) - expect(PaymentProviderServiceMock.refreshSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.refreshSession).toBeCalledTimes(0) expect(DefaultProviderMock.deletePayment).toBeCalledTimes(0) - expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0) + expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) }) }) @@ -695,7 +682,7 @@ describe("PaymentCollectionService", () => { expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( 2 ) - expect(PaymentProviderServiceMock.createPaymentNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes( 2 ) expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) @@ -710,7 +697,7 @@ describe("PaymentCollectionService", () => { expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( 1 ) - expect(PaymentProviderServiceMock.createPaymentNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes( 1 ) expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) @@ -725,7 +712,7 @@ describe("PaymentCollectionService", () => { expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( 0 ) - expect(PaymentProviderServiceMock.createPaymentNew).toHaveBeenCalledTimes( + expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes( 0 ) expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(0) diff --git a/packages/medusa/src/services/__tests__/payment-provider.js b/packages/medusa/src/services/__tests__/payment-provider.js index 12ef0f32bd..99a3b26eb4 100644 --- a/packages/medusa/src/services/__tests__/payment-provider.js +++ b/packages/medusa/src/services/__tests__/payment-provider.js @@ -1,17 +1,15 @@ -import { MockManager, MockRepository } from "medusa-test-utils" +import { asValue, createContainer } from "awilix" +import { MockRepository } from "medusa-test-utils" import PaymentProviderService from "../payment-provider" +import { defaultContainer } from "../__fixtures__/payment-provider" import { testPayServiceMock } from "../__mocks__/test-pay" -import { FlagRouter } from "../../utils/flag-router" describe("PaymentProviderService", () => { describe("retrieveProvider", () => { - const container = { - manager: MockManager, - paymentSessionRepository: MockRepository(), - pp_default_provider: "good", - } + const container = createContainer({}, defaultContainer) + container.register("pp_default_provider", asValue("good")) - const providerService = new PaymentProviderService(container) + const providerService = container.resolve("paymentProviderService") it("successfully retrieves payment provider", () => { const provider = providerService.retrieveProvider("default_provider") @@ -30,56 +28,78 @@ describe("PaymentProviderService", () => { }) describe("createSession", () => { - const createPayment = jest.fn().mockReturnValue(Promise.resolve()) - const container = { - manager: MockManager, - paymentSessionRepository: MockRepository(), - pp_default_provider: { + const container = createContainer({}, defaultContainer) + container.register( + "pp_default_provider", + asValue({ withTransaction: function () { return this }, - createPayment, - }, - } + createPayment: jest.fn().mockReturnValue(Promise.resolve({})), + }) + ) - const providerService = new PaymentProviderService(container) + const providerService = container.resolve("paymentProviderService") it("successfully creates session", async () => { await providerService.createSession("default_provider", { + object: "cart", + region: { + currency_code: "usd", + }, total: 100, }) - expect(createPayment).toBeCalledTimes(1) - expect(createPayment).toBeCalledWith({ + const defaultProvider = container.resolve("pp_default_provider") + + expect(defaultProvider.createPayment).toBeCalledTimes(1) + expect(defaultProvider.createPayment).toBeCalledWith({ + amount: 100, + object: "cart", total: 100, + region: { + currency_code: "usd", + }, + cart: { + context: undefined, + email: undefined, + id: undefined, + shipping_address: undefined, + shipping_methods: undefined, + }, + currency_code: "usd", }) }) }) describe("updateSession", () => { - const updatePayment = jest.fn().mockReturnValue(Promise.resolve()) - - const container = { - manager: MockManager, - paymentSessionRepository: MockRepository({ - findOne: () => - Promise.resolve({ - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }), - }), - pp_default_provider: { + const container = createContainer({}, defaultContainer) + container.register( + "paymentSessionRepository", + asValue( + MockRepository({ + findOne: () => + Promise.resolve({ + id: "session", + provider_id: "default_provider", + data: { + id: "1234", + }, + }), + }) + ) + ) + container.register( + "pp_default_provider", + asValue({ withTransaction: function () { return this }, - updatePayment, - }, - } + updatePayment: jest.fn().mockReturnValue(Promise.resolve()), + }) + ) - const providerService = new PaymentProviderService(container) + const providerService = container.resolve("paymentProviderService") it("successfully creates session", async () => { await providerService.updateSession( @@ -91,15 +111,28 @@ describe("PaymentProviderService", () => { }, }, { + object: "cart", total: 100, } ) - expect(updatePayment).toBeCalledTimes(1) - expect(updatePayment).toBeCalledWith( + const defaultProvider = container.resolve("pp_default_provider") + + expect(defaultProvider.updatePayment).toBeCalledTimes(1) + expect(defaultProvider.updatePayment).toBeCalledWith( { id: "1234" }, { + object: "cart", + amount: 100, total: 100, + cart: { + context: undefined, + email: undefined, + id: undefined, + shipping_address: undefined, + shipping_methods: undefined, + }, + currency_code: undefined, } ) }) @@ -107,50 +140,53 @@ describe("PaymentProviderService", () => { }) describe(`PaymentProviderService`, () => { - const featureFlagRouter = new FlagRouter({ - order_editing: false, - }) - - const container = { - manager: MockManager, - paymentSessionRepository: MockRepository({ - findOne: () => - Promise.resolve({ - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }), - }), - paymentRepository: MockRepository({ - findOne: () => - Promise.resolve({ - id: "pay_jadazdjk", - provider_id: "default_provider", - data: { - id: "1234", - }, - }), - find: () => - Promise.resolve([ - { + const container = createContainer({}, defaultContainer) + container.register("pp_default_provider", asValue(testPayServiceMock)) + container.register( + "paymentSessionRepository", + asValue( + MockRepository({ + findOne: () => + Promise.resolve({ + id: "session", + provider_id: "default_provider", + data: { + id: "1234", + }, + }), + }) + ) + ) + container.register( + "paymentRepository", + asValue( + MockRepository({ + findOne: () => + Promise.resolve({ id: "pay_jadazdjk", provider_id: "default_provider", data: { id: "1234", }, - captured_at: new Date(), - amount: 100, - amount_refunded: 0, - }, - ]), - }), - refundRepository: MockRepository(), - pp_default_provider: testPayServiceMock, - featureFlagRouter, - } - const providerService = new PaymentProviderService(container) + }), + find: () => + Promise.resolve([ + { + id: "pay_jadazdjk", + provider_id: "default_provider", + data: { + id: "1234", + }, + captured_at: new Date(), + amount: 100, + amount_refunded: 0, + }, + ]), + }) + ) + ) + + const providerService = container.resolve("paymentProviderService") afterEach(() => { jest.clearAllMocks() @@ -163,12 +199,29 @@ describe(`PaymentProviderService`, () => { it("successfully creates session", async () => { await providerService.createSession("default_provider", { + object: "cart", + region: { + currency_code: "usd", + }, total: 100, }) expect(testPayServiceMock.createPayment).toBeCalledTimes(1) expect(testPayServiceMock.createPayment).toBeCalledWith({ + amount: 100, + object: "cart", total: 100, + region: { + currency_code: "usd", + }, + cart: { + context: undefined, + email: undefined, + id: undefined, + shipping_address: undefined, + shipping_methods: undefined, + }, + currency_code: "usd", }) }) @@ -182,6 +235,7 @@ describe(`PaymentProviderService`, () => { }, }, { + object: "cart", total: 100, } ) @@ -190,7 +244,16 @@ describe(`PaymentProviderService`, () => { expect(testPayServiceMock.updatePayment).toBeCalledWith( { id: "1234" }, { + amount: 100, + object: "cart", total: 100, + cart: { + context: undefined, + email: undefined, + id: undefined, + shipping_address: undefined, + shipping_methods: undefined, + }, } ) }) @@ -205,7 +268,9 @@ describe(`PaymentProviderService`, () => { }, }, { - total: 100, + provider_id: "default_provider", + amount: 100, + currency_code: "usd", } ) diff --git a/packages/medusa/src/services/batch-job.ts b/packages/medusa/src/services/batch-job.ts index 5f682bfc11..e331e21f69 100644 --- a/packages/medusa/src/services/batch-job.ts +++ b/packages/medusa/src/services/batch-job.ts @@ -11,8 +11,8 @@ import { } from "../types/batch-job" import { FindConfig } from "../types/common" import { TransactionBaseService } from "../interfaces" -import { buildQuery, isDefined } from "../utils" -import { MedusaError } from "medusa-core-utils" +import { buildQuery } from "../utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EventBusService, StrategyResolverService } from "./index" import { Request } from "express" diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index 8fb3ccda1f..a07e692069 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -1,5 +1,5 @@ import { isEmpty, isEqual } from "lodash" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager, In } from "typeorm" import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces" import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" @@ -34,7 +34,7 @@ import { TotalField, WithRequiredProperty, } from "../types/common" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { FlagRouter } from "../utils/flag-router" import { validateEmail } from "../utils/is-email" import CustomShippingOptionService from "./custom-shipping-option" @@ -54,6 +54,7 @@ import ShippingOptionService from "./shipping-option" import StoreService from "./store" import TaxProviderService from "./tax-provider" import TotalsService from "./totals" +import { PaymentSessionInput } from "../types/payment" type InjectedDependencies = { manager: EntityManager @@ -1678,6 +1679,12 @@ class CartService extends TransactionBaseService { ) const { total, region } = cart + const partialSessionInput: Omit = { + cart: cart as Cart, + customer: cart.customer, + amount: cart.total, + currency_code: cart.region.currency_code, + } // If there are existing payment sessions ensure that these are up to date const seen: string[] = [] @@ -1695,9 +1702,15 @@ class CartService extends TransactionBaseService { .deleteSession(paymentSession) } else { seen.push(paymentSession.provider_id) + + const paymentSessionInput = { + ...partialSessionInput, + provider_id: paymentSession.provider_id, + } + return this.paymentProviderService_ .withTransaction(transactionManager) - .updateSession(paymentSession, cart) + .updateSession(paymentSession, paymentSessionInput) } }) ) @@ -1707,9 +1720,14 @@ class CartService extends TransactionBaseService { // If only one payment session exists, we preselect it if (region.payment_providers.length === 1 && !cart.payment_session) { const paymentProvider = region.payment_providers[0] + const paymentSessionInput = { + ...partialSessionInput, + provider_id: paymentProvider.id, + } + const paymentSession = await this.paymentProviderService_ .withTransaction(transactionManager) - .createSession(paymentProvider.id, cart) + .createSession(paymentSessionInput) paymentSession.is_selected = true @@ -1718,9 +1736,14 @@ class CartService extends TransactionBaseService { await Promise.all( region.payment_providers.map(async (paymentProvider) => { if (!seen.includes(paymentProvider.id)) { + const paymentSessionInput = { + ...partialSessionInput, + provider_id: paymentProvider.id, + } + return this.paymentProviderService_ .withTransaction(transactionManager) - .createSession(paymentProvider.id, cart) + .createSession(paymentSessionInput) } return }) @@ -1792,7 +1815,7 @@ class CartService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { + const cart = await this.retrieveWithTotals(cartId, { relations: ["payment_sessions"], }) @@ -1805,7 +1828,13 @@ class CartService extends TransactionBaseService { // Delete the session with the provider await this.paymentProviderService_ .withTransaction(transactionManager) - .refreshSession(paymentSession, cart) + .refreshSession(paymentSession, { + cart: cart as Cart, + customer: cart.customer, + amount: cart.total, + currency_code: cart.region.currency_code, + provider_id: providerId, + }) } } diff --git a/packages/medusa/src/services/claim-item.ts b/packages/medusa/src/services/claim-item.ts index e7e1fb9f30..bdc83b5489 100644 --- a/packages/medusa/src/services/claim-item.ts +++ b/packages/medusa/src/services/claim-item.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { ClaimImage, ClaimItem, ClaimTag } from "../models" @@ -7,7 +7,7 @@ import { ClaimItemRepository } from "../repositories/claim-item" import { ClaimTagRepository } from "../repositories/claim-tag" import { CreateClaimItemInput } from "../types/claim" import { FindConfig, Selector } from "../types/common" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import EventBusService from "./event-bus" import LineItemService from "./line-item" diff --git a/packages/medusa/src/services/claim.ts b/packages/medusa/src/services/claim.ts index bfe06eaa8e..38b05cf42b 100644 --- a/packages/medusa/src/services/claim.ts +++ b/packages/medusa/src/services/claim.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { @@ -16,7 +16,7 @@ import { LineItemRepository } from "../repositories/line-item" import { ShippingMethodRepository } from "../repositories/shipping-method" import { CreateClaimInput, UpdateClaimInput } from "../types/claim" import { FindConfig } from "../types/common" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import ClaimItemService from "./claim-item" import EventBusService from "./event-bus" import FulfillmentService from "./fulfillment" diff --git a/packages/medusa/src/services/customer-group.ts b/packages/medusa/src/services/customer-group.ts index 37afd0b64e..4d52dd9b4d 100644 --- a/packages/medusa/src/services/customer-group.ts +++ b/packages/medusa/src/services/customer-group.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager, ILike } from "typeorm" import { CustomerService } from "." import { CustomerGroup } from ".." @@ -8,13 +8,7 @@ import { } from "../repositories/customer-group" import { FindConfig, Selector } from "../types/common" import { CustomerGroupUpdate } from "../types/customer-groups" -import { - buildQuery, - isDefined, - isString, - PostgresError, - setMetadata, -} from "../utils" +import { buildQuery, isString, PostgresError, setMetadata } from "../utils" import { TransactionBaseService } from "../interfaces" type CustomerGroupConstructorProps = { @@ -35,6 +29,7 @@ class CustomerGroupService extends TransactionBaseService { customerGroupRepository, customerService, }: CustomerGroupConstructorProps) { + // eslint-disable-next-line prefer-rest-params super(arguments[0]) this.manager_ = manager diff --git a/packages/medusa/src/services/customer.ts b/packages/medusa/src/services/customer.ts index 52ba9b612a..784b22b760 100644 --- a/packages/medusa/src/services/customer.ts +++ b/packages/medusa/src/services/customer.ts @@ -1,5 +1,5 @@ import jwt from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import Scrypt from "scrypt-kdf" import { DeepPartial, EntityManager } from "typeorm" import { EventBusService } from "." @@ -10,7 +10,7 @@ import { AddressRepository } from "../repositories/address" import { CustomerRepository } from "../repositories/customer" import { AddressCreatePayload, FindConfig, Selector } from "../types/common" import { CreateCustomerInput, UpdateCustomerInput } from "../types/customers" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" type InjectedDependencies = { manager: EntityManager diff --git a/packages/medusa/src/services/discount-condition.ts b/packages/medusa/src/services/discount-condition.ts index 058b468ab5..1932883209 100644 --- a/packages/medusa/src/services/discount-condition.ts +++ b/packages/medusa/src/services/discount-condition.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { EventBusService } from "." import { @@ -14,7 +14,7 @@ import { DiscountConditionRepository } from "../repositories/discount-condition" import { FindConfig } from "../types/common" import { DiscountConditionInput } from "../types/discount" import { TransactionBaseService } from "../interfaces" -import { buildQuery, isDefined, PostgresError } from "../utils" +import { buildQuery, PostgresError } from "../utils" type InjectedDependencies = { manager: EntityManager diff --git a/packages/medusa/src/services/discount.ts b/packages/medusa/src/services/discount.ts index cfa436cce2..23ea97b274 100644 --- a/packages/medusa/src/services/discount.ts +++ b/packages/medusa/src/services/discount.ts @@ -1,6 +1,6 @@ import { parse, toSeconds } from "iso8601-duration" import { isEmpty, omit } from "lodash" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Brackets, DeepPartial, @@ -36,7 +36,7 @@ import { UpdateDiscountInput, UpdateDiscountRuleInput, } from "../types/discount" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { isFuture, isPast } from "../utils/date-helpers" import { FlagRouter } from "../utils/flag-router" import CustomerService from "./customer" diff --git a/packages/medusa/src/services/draft-order.ts b/packages/medusa/src/services/draft-order.ts index ae89a726bc..58a7451c41 100644 --- a/packages/medusa/src/services/draft-order.ts +++ b/packages/medusa/src/services/draft-order.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Brackets, EntityManager, FindManyOptions, UpdateResult } from "typeorm" import { TransactionBaseService } from "../interfaces" import { Cart, CartType, DraftOrder, DraftOrderStatus } from "../models" @@ -7,7 +7,7 @@ import { OrderRepository } from "../repositories/order" import { PaymentRepository } from "../repositories/payment" import { ExtendedFindConfig, FindConfig } from "../types/common" import { DraftOrderCreateProps } from "../types/draft-orders" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import CartService from "./cart" import CustomShippingOptionService from "./custom-shipping-option" import EventBusService from "./event-bus" diff --git a/packages/medusa/src/services/fulfillment.ts b/packages/medusa/src/services/fulfillment.ts index 56de2b12b9..7fab2dd642 100644 --- a/packages/medusa/src/services/fulfillment.ts +++ b/packages/medusa/src/services/fulfillment.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { ShippingProfileService } from "." import { TransactionBaseService } from "../interfaces" @@ -13,7 +13,7 @@ import { FulfillmentItemPartition, FulFillmentItemType, } from "../types/fulfillment" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import FulfillmentProviderService from "./fulfillment-provider" import LineItemService from "./line-item" import TotalsService from "./totals" diff --git a/packages/medusa/src/services/gift-card.ts b/packages/medusa/src/services/gift-card.ts index aff58df16f..f69f33824a 100644 --- a/packages/medusa/src/services/gift-card.ts +++ b/packages/medusa/src/services/gift-card.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import randomize from "randomatic" import { EntityManager } from "typeorm" import { EventBusService } from "." @@ -17,7 +17,7 @@ import { CreateGiftCardTransactionInput, UpdateGiftCardInput, } from "../types/gift-card" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import RegionService from "./region" type InjectedDependencies = { diff --git a/packages/medusa/src/services/idempotency-key.ts b/packages/medusa/src/services/idempotency-key.ts index 5a492df8b8..d13cca507b 100644 --- a/packages/medusa/src/services/idempotency-key.ts +++ b/packages/medusa/src/services/idempotency-key.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { v4 } from "uuid" import { TransactionBaseService } from "../interfaces" import { DeepPartial, EntityManager } from "typeorm" @@ -8,7 +8,6 @@ import { CreateIdempotencyKeyInput, IdempotencyCallbackResult, } from "../types/idempotency-key" -import { isDefined } from "../utils" const KEY_LOCKED_TIMEOUT = 1000 diff --git a/packages/medusa/src/services/inventory.ts b/packages/medusa/src/services/inventory.ts index 73559f751c..7d6f26592f 100644 --- a/packages/medusa/src/services/inventory.ts +++ b/packages/medusa/src/services/inventory.ts @@ -1,9 +1,8 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { TransactionBaseService } from "../interfaces" import { EntityManager } from "typeorm" import ProductVariantService from "./product-variant" import { ProductVariant } from "../models" -import { isDefined } from "../utils" type InventoryServiceProps = { manager: EntityManager diff --git a/packages/medusa/src/services/line-item-adjustment.ts b/packages/medusa/src/services/line-item-adjustment.ts index caa2125742..a23184e7ce 100644 --- a/packages/medusa/src/services/line-item-adjustment.ts +++ b/packages/medusa/src/services/line-item-adjustment.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager, In } from "typeorm" import { Cart, DiscountRuleType, LineItem, LineItemAdjustment } from "../models" @@ -7,7 +7,7 @@ import { FindConfig } from "../types/common" import { FilterableLineItemAdjustmentProps } from "../types/line-item-adjustment" import DiscountService from "./discount" import { TransactionBaseService } from "../interfaces" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { CalculationContextData } from "../types/totals" type LineItemAdjustmentServiceProps = { diff --git a/packages/medusa/src/services/new-totals.ts b/packages/medusa/src/services/new-totals.ts index 50efa2c671..17a3aeec8c 100644 --- a/packages/medusa/src/services/new-totals.ts +++ b/packages/medusa/src/services/new-totals.ts @@ -18,8 +18,8 @@ import { TaxProviderService } from "./index" import { LineAllocationsMap } from "../types/totals" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" import { FlagRouter } from "../utils/flag-router" -import { calculatePriceTaxAmount, isDefined } from "../utils" -import { MedusaError } from "medusa-core-utils" +import { calculatePriceTaxAmount } from "../utils" +import { isDefined, MedusaError } from "medusa-core-utils" type LineItemTotals = { unit_price: number diff --git a/packages/medusa/src/services/note.ts b/packages/medusa/src/services/note.ts index d14513ebad..c284ff225e 100644 --- a/packages/medusa/src/services/note.ts +++ b/packages/medusa/src/services/note.ts @@ -1,11 +1,11 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { NoteRepository } from "../repositories/note" import EventBusService from "./event-bus" import { FindConfig, Selector } from "../types/common" import { Note } from "../models" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import { CreateNoteInput } from "../types/note" type InjectedDependencies = { diff --git a/packages/medusa/src/services/oauth.ts b/packages/medusa/src/services/oauth.ts index 205e6d861a..4a79a81eb4 100644 --- a/packages/medusa/src/services/oauth.ts +++ b/packages/medusa/src/services/oauth.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { Oauth as OAuthModel } from "../models" @@ -6,7 +6,7 @@ import { OauthRepository } from "../repositories/oauth" import { Selector } from "../types/common" import { MedusaContainer } from "../types/global" import { CreateOauthInput, UpdateOauthInput } from "../types/oauth" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import EventBusService from "./event-bus" type InjectedDependencies = MedusaContainer & { diff --git a/packages/medusa/src/services/order-edit.ts b/packages/medusa/src/services/order-edit.ts index df1cbedd0c..f72be7682f 100644 --- a/packages/medusa/src/services/order-edit.ts +++ b/packages/medusa/src/services/order-edit.ts @@ -1,8 +1,8 @@ import { DeepPartial, EntityManager, ILike, IsNull } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { FindConfig, Selector } from "../types/common" -import { buildQuery, isDefined, isString } from "../utils" +import { buildQuery, isString } from "../utils" import { OrderEditRepository } from "../repositories/order-edit" import { Cart, diff --git a/packages/medusa/src/services/order.ts b/packages/medusa/src/services/order.ts index 99ade188d2..ff65646fb8 100644 --- a/packages/medusa/src/services/order.ts +++ b/packages/medusa/src/services/order.ts @@ -1,5 +1,4 @@ -import jwt, { JwtPayload } from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Brackets, EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" @@ -28,7 +27,7 @@ import { } from "../types/fulfillment" import { UpdateOrderInput } from "../types/orders" import { CreateShippingMethodDto } from "../types/shipping-options" -import { buildQuery, isDefined, isString, setMetadata } from "../utils" +import { buildQuery, isString, setMetadata } from "../utils" import { FlagRouter } from "../utils/flag-router" import CartService from "./cart" import CustomerService from "./customer" @@ -46,8 +45,6 @@ import ShippingOptionService from "./shipping-option" import ShippingProfileService from "./shipping-profile" import TotalsService from "./totals" import { NewTotalsService, TaxProviderService } from "./index" -import { ConfigModule } from "../types/global" -import logger from "../loaders/logger" export const ORDER_CART_ALREADY_EXISTS_ERROR = "Order from cart already exists" diff --git a/packages/medusa/src/services/payment-collection.ts b/packages/medusa/src/services/payment-collection.ts index bf86615b9d..fc4434a852 100644 --- a/packages/medusa/src/services/payment-collection.ts +++ b/packages/medusa/src/services/payment-collection.ts @@ -1,8 +1,8 @@ import { DeepPartial, EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { FindConfig } from "../types/common" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { PaymentCollectionRepository } from "../repositories/payment-collection" import { PaymentCollection, @@ -21,8 +21,8 @@ import { CreatePaymentCollectionInput, PaymentCollectionsSessionsBatchInput, PaymentCollectionsSessionsInput, - PaymentProviderDataInput, } from "../types/payment-collection" +import { CreatePaymentInput, PaymentSessionInput } from "../types/payment" type InjectedDependencies = { manager: EntityManager @@ -194,10 +194,10 @@ export default class PaymentCollectionService extends TransactionBaseService { } if ( - [ + ![ PaymentCollectionStatus.CANCELED, PaymentCollectionStatus.NOT_PAID, - ].includes(paymentCollection.status) === false + ].includes(paymentCollection.status) ) { throw new MedusaError( MedusaError.Types.NOT_ALLOWED, @@ -251,10 +251,14 @@ export default class PaymentCollectionService extends TransactionBaseService { ) } - sessionsInput = sessionsInput.filter((session) => { - return !!payCol.region.payment_providers.find(({ id }) => { - return id === session.provider_id + const payColRegionProviderMap = new Map( + payCol.region.payment_providers.map((provider) => { + return [provider.id, provider] }) + ) + + sessionsInput = sessionsInput.filter((session) => { + return !!payColRegionProviderMap.get(session.provider_id) }) if (!this.isValidTotalAmount(payCol.amount, sessionsInput)) { @@ -273,15 +277,30 @@ export default class PaymentCollectionService extends TransactionBaseService { }) .catch(() => null) + const payColSessionMap = new Map( + (payCol.payment_sessions ?? []).map((session) => { + return [session.id, session] + }) + ) + + const paymentProviderTx = + this.paymentProviderService_.withTransaction(manager) + const selectedSessionIds: string[] = [] const paymentSessions: PaymentSession[] = [] for (const session of sessionsInput) { - const existingSession = payCol.payment_sessions?.find( - (sess) => session.session_id === sess?.id - ) + const existingSession = + session.session_id && payColSessionMap.get(session.session_id) - const inputData: PaymentProviderDataInput = { + const inputData: PaymentSessionInput = { + cart: { + email: customer?.email || "", + context: {}, + shipping_methods: [], + shipping_address: null, + id: "", + }, resource_id: payCol.id, currency_code: payCol.currency_code, amount: session.amount, @@ -289,21 +308,19 @@ export default class PaymentCollectionService extends TransactionBaseService { customer, } + let paymentSession + if (existingSession) { - const paymentSession = await this.paymentProviderService_ - .withTransaction(manager) - .updateSessionNew(existingSession, inputData) - - selectedSessionIds.push(existingSession.id) - paymentSessions.push(paymentSession) + paymentSession = await paymentProviderTx.updateSession( + existingSession, + inputData + ) } else { - const paymentSession = await this.paymentProviderService_ - .withTransaction(manager) - .createSessionNew(inputData) - - selectedSessionIds.push(paymentSession.id) - paymentSessions.push(paymentSession) + paymentSession = await paymentProviderTx.createSession(inputData) } + + selectedSessionIds.push(paymentSession.id) + paymentSessions.push(paymentSession) } if (payCol.payment_sessions?.length) { @@ -312,15 +329,16 @@ export default class PaymentCollectionService extends TransactionBaseService { ) if (removeSessions.length) { - await paymentCollectionRepository.deleteMultiple( + await paymentCollectionRepository.delete( removeSessions.map((sess) => sess.id) ) + const paymentProviderTx = + this.paymentProviderService_.withTransaction(manager) + Promise.all( removeSessions.map(async (sess) => - this.paymentProviderService_ - .withTransaction(manager) - .deleteSessionNew(sess) + paymentProviderTx.deleteSession(sess) ) ).catch(() => void 0) } @@ -335,7 +353,7 @@ export default class PaymentCollectionService extends TransactionBaseService { /** * Manages a single payment sessions of a payment collection. * @param paymentCollectionId - the id of the payment collection - * @param sessionsInput - object containing payment session info + * @param sessionInput - object containing payment session info * @param customerId - the id of the customer * @return the payment collection and its payment session. */ @@ -381,7 +399,15 @@ export default class PaymentCollectionService extends TransactionBaseService { .catch(() => null) const paymentSessions: PaymentSession[] = [] - const inputData: PaymentProviderDataInput = { + + const inputData: PaymentSessionInput = { + cart: { + email: customer?.email || "", + context: {}, + shipping_methods: [], + shipping_address: null, + id: "", + }, resource_id: payCol.id, currency_code: payCol.currency_code, amount: payCol.amount, @@ -396,13 +422,13 @@ export default class PaymentCollectionService extends TransactionBaseService { if (existingSession) { const paymentSession = await this.paymentProviderService_ .withTransaction(manager) - .updateSessionNew(existingSession, inputData) + .updateSession(existingSession, inputData) paymentSessions.push(paymentSession) } else { const paymentSession = await this.paymentProviderService_ .withTransaction(manager) - .createSessionNew(inputData) + .createSession(inputData) paymentSessions.push(paymentSession) @@ -411,15 +437,16 @@ export default class PaymentCollectionService extends TransactionBaseService { ) if (removeSessions.length) { - await paymentCollectionRepository.deleteMultiple( + await paymentCollectionRepository.delete( removeSessions.map((sess) => sess.id) ) + const paymentProviderTx = + this.paymentProviderService_.withTransaction(manager) + Promise.all( removeSessions.map(async (sess) => - this.paymentProviderService_ - .withTransaction(manager) - .deleteSessionNew(sess) + paymentProviderTx.deleteSession(sess) ) ).catch(() => void 0) } @@ -487,7 +514,14 @@ export default class PaymentCollectionService extends TransactionBaseService { }) .catch(() => null) - const inputData: PaymentProviderDataInput = { + const inputData: PaymentSessionInput = { + cart: { + email: customer?.email || "", + context: {}, + shipping_methods: [], + shipping_address: null, + id: "", + }, resource_id: payCol.id, currency_code: payCol.currency_code, amount: session.amount, @@ -497,7 +531,7 @@ export default class PaymentCollectionService extends TransactionBaseService { const sessionRefreshed = await this.paymentProviderService_ .withTransaction(manager) - .refreshSessionNew(session, inputData) + .refreshSession(session, inputData) payCol.payment_sessions = payCol.payment_sessions.map((sess) => { if (sess.id === sessionId) { @@ -581,6 +615,9 @@ export default class PaymentCollectionService extends TransactionBaseService { ) } + const paymentProviderTx = + this.paymentProviderService_.withTransaction(manager) + let authorizedAmount = 0 for (let i = 0; i < payCol.payment_sessions.length; i++) { const session = payCol.payment_sessions[i] @@ -594,32 +631,27 @@ export default class PaymentCollectionService extends TransactionBaseService { continue } - const auth = await this.paymentProviderService_ - .withTransaction(manager) - .authorizePayment(session, context) + const paymentSession = await paymentProviderTx.authorizePayment( + session, + context + ) - if (auth) { - payCol.payment_sessions[i] = auth + if (paymentSession) { + payCol.payment_sessions[i] = paymentSession } - if (auth?.status === PaymentSessionStatus.AUTHORIZED) { + if (paymentSession?.status === PaymentSessionStatus.AUTHORIZED) { authorizedAmount += session.amount - const inputData: Omit & { - payment_session: PaymentSession - } = { + const inputData: CreatePaymentInput = { amount: session.amount, currency_code: payCol.currency_code, provider_id: session.provider_id, resource_id: payCol.id, - payment_session: auth, + payment_session: paymentSession, } - payCol.payments.push( - await this.paymentProviderService_ - .withTransaction(manager) - .createPaymentNew(inputData) - ) + payCol.payments.push(await paymentProviderTx.createPayment(inputData)) } } diff --git a/packages/medusa/src/services/payment-provider.ts b/packages/medusa/src/services/payment-provider.ts index f10a9714f9..07cb1faa44 100644 --- a/packages/medusa/src/services/payment-provider.ts +++ b/packages/medusa/src/services/payment-provider.ts @@ -1,12 +1,17 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { BasePaymentService } from "medusa-interfaces" -import { AbstractPaymentService, TransactionBaseService } from "../interfaces" +import { + AbstractPaymentService, + PaymentContext, + PaymentSessionResponse, + TransactionBaseService, +} from "../interfaces" import { EntityManager } from "typeorm" import { PaymentSessionRepository } from "../repositories/payment-session" import { PaymentRepository } from "../repositories/payment" import { RefundRepository } from "../repositories/refund" import { PaymentProviderRepository } from "../repositories/payment-provider" -import { buildQuery } from "../utils" +import { buildQuery, isString } from "../utils" import { FindConfig, Selector } from "../types/common" import { Cart, @@ -16,11 +21,12 @@ import { PaymentSessionStatus, Refund, } from "../models" -import { PaymentProviderDataInput } from "../types/payment-collection" import { FlagRouter } from "../utils/flag-router" import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" import PaymentService from "./payment" import { Logger } from "../types/global" +import { CreatePaymentInput, PaymentSessionInput } from "../types/payment" +import { CustomerService } from "./index" type PaymentProviderKey = `pp_${string}` | "systemPaymentProviderService" type InjectedDependencies = { @@ -30,6 +36,7 @@ type InjectedDependencies = { paymentRepository: typeof PaymentRepository refundRepository: typeof RefundRepository paymentService: PaymentService + customerService: CustomerService featureFlagRouter: FlagRouter logger: Logger } & { @@ -50,6 +57,7 @@ export default class PaymentProviderService extends TransactionBaseService { protected readonly paymentProviderRepository_: typeof PaymentProviderRepository protected readonly paymentRepository_: typeof PaymentRepository protected readonly refundRepository_: typeof RefundRepository + protected readonly customerService_: CustomerService protected readonly logger_: Logger protected readonly featureFlagRouter_: FlagRouter @@ -63,6 +71,7 @@ export default class PaymentProviderService extends TransactionBaseService { this.paymentProviderRepository_ = container.paymentProviderRepository this.paymentRepository_ = container.paymentRepository this.refundRepository_ = container.refundRepository + this.customerService_ = container.customerService this.featureFlagRouter_ = container.featureFlagRouter this.logger_ = container.logger } @@ -165,55 +174,59 @@ export default class PaymentProviderService extends TransactionBaseService { /** * Creates a payment session with the given provider. - * @param providerId - the id of the provider to create payment with + * @param providerIdOrSessionInput - the id of the provider to create payment with or the input data * @param cart - a cart object used to calculate the amount, etc. from * @return the payment session */ - async createSession(providerId: string, cart: Cart): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const provider = this.retrieveProvider(providerId) - const sessionData = await provider - .withTransaction(transactionManager) - .createPayment(cart) - - const sessionRepo = transactionManager.getCustomRepository( - this.paymentSessionRepository_ - ) - - const toCreate = { - cart_id: cart.id, - provider_id: providerId, - data: sessionData, - status: "pending", - } - - const created = sessionRepo.create(toCreate) - return await sessionRepo.save(created) - }) - } - - async createSessionNew( - sessionInput: PaymentProviderDataInput + async createSession< + TInput extends string | PaymentSessionInput = string | PaymentSessionInput + >( + providerIdOrSessionInput: TInput, + ...[cart]: TInput extends string ? [Cart] : [never?] ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const provider = this.retrieveProvider(sessionInput.provider_id) - const sessionData = await provider - .withTransaction(transactionManager) - .createPaymentNew(sessionInput) + const providerId = isString(providerIdOrSessionInput) + ? providerIdOrSessionInput + : providerIdOrSessionInput.provider_id + const data = ( + isString(providerIdOrSessionInput) ? cart : providerIdOrSessionInput + ) as Cart | PaymentSessionInput - const sessionRepo = transactionManager.getCustomRepository( - this.paymentSessionRepository_ + const provider = this.retrieveProvider(providerId) + const context = this.buildPaymentContext(data) + + if (!isDefined(context.currency_code) || !isDefined(context.amount)) { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "`currency_code` and `amount` are required to create payment session." + ) + } + + const paymentResponse = await provider + .withTransaction(transactionManager) + .createPayment(context) + + const sessionData = paymentResponse.session_data ?? paymentResponse + + await this.processUpdateRequestsData( + { + customer: { id: context.customer?.id }, + }, + paymentResponse ) - const toCreate = { - provider_id: sessionInput.provider_id, - data: sessionData, - status: "pending", - amount: sessionInput.amount, - } as PaymentSession + const amount = this.featureFlagRouter_.isFeatureEnabled( + OrderEditingFeatureFlag.key + ) + ? context.amount + : undefined - const created = sessionRepo.create(toCreate) - return await sessionRepo.save(created) + return await this.saveSession(providerId, { + cartId: context.id, + sessionData, + status: PaymentSessionStatus.PENDING, + amount, + }) }) } @@ -222,16 +235,22 @@ export default class PaymentProviderService extends TransactionBaseService { * This means, that we delete the current one and create a new. * @param paymentSession - the payment session object to * update - * @param cart - a cart object used to calculate the amount, etc. from + * @param sessionInput * @return the payment session */ async refreshSession( - paymentSession: PaymentSession, - cart: Cart + paymentSession: { + id: string + data: Record + provider_id: string + }, + sessionInput: PaymentSessionInput ): Promise { return this.atomicPhase_(async (transactionManager) => { const session = await this.retrieveSession(paymentSession.id) - const provider = this.retrieveProvider(paymentSession.provider_id) + const provider = this.retrieveProvider( + paymentSession.provider_id + ) await provider.withTransaction(transactionManager).deletePayment(session) const sessionRepo = transactionManager.getCustomRepository( @@ -239,88 +258,44 @@ export default class PaymentProviderService extends TransactionBaseService { ) await sessionRepo.remove(session) - - const sessionData = await provider - .withTransaction(transactionManager) - .createPayment(cart) - - const toCreate = { - cart_id: cart.id, - provider_id: session.provider_id, - data: sessionData, - is_selected: true, - status: "pending", - } - - const created = sessionRepo.create(toCreate) - return await sessionRepo.save(created) - }) - } - - async refreshSessionNew( - paymentSession: PaymentSession, - sessionInput: PaymentProviderDataInput - ): Promise { - return this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id) - const provider = this.retrieveProvider(paymentSession.provider_id) - - await provider.withTransaction(transactionManager).deletePayment(session) - - const sessionRepo = transactionManager.getCustomRepository( - this.paymentSessionRepository_ - ) - - await sessionRepo.remove(session) - - return await this.createSessionNew(sessionInput) + return await this.createSession(sessionInput) }) } /** - * Updates an existing payment session. - * @param paymentSession - the payment session object to - * update - * @param cart - the cart object to update for - * @return the updated payment session + * Update a payment session with the given provider. + * @param paymentSession - The paymentSession to update + * @param sessionInput + * @return the payment session */ async updateSession( - paymentSession: PaymentSession, - cart: Cart + paymentSession: { + id: string + data: Record + provider_id: string + }, + sessionInput: Cart | PaymentSessionInput ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id) - const provider = this.retrieveProvider(paymentSession.provider_id) - session.data = await provider - .withTransaction(transactionManager) - .updatePayment(paymentSession.data, cart) - - const sessionRepo = transactionManager.getCustomRepository( - this.paymentSessionRepository_ - ) - return await sessionRepo.save(session) - }) - } - - async updateSessionNew( - paymentSession: PaymentSession, - sessionInput: PaymentProviderDataInput - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id) const provider = this.retrieveProvider(paymentSession.provider_id) - session.amount = sessionInput.amount - paymentSession.data.amount = sessionInput.amount - session.data = await provider + const context = this.buildPaymentContext(sessionInput) + + const sessionData = await provider .withTransaction(transactionManager) - .updatePaymentNew(paymentSession.data, sessionInput) + .updatePayment(paymentSession.data, context) - const sessionRepo = transactionManager.getCustomRepository( - this.paymentSessionRepository_ + const amount = this.featureFlagRouter_.isFeatureEnabled( + OrderEditingFeatureFlag.key ) + ? context.amount + : undefined - return await sessionRepo.save(session) + return await this.saveSession(paymentSession.provider_id, { + payment_session_id: paymentSession.id, + sessionData, + amount, + }) }) } @@ -349,15 +324,6 @@ export default class PaymentProviderService extends TransactionBaseService { }) } - async deleteSessionNew(paymentSession: PaymentSession): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const provider = this.retrieveProvider(paymentSession.provider_id) - return await provider - .withTransaction(transactionManager) - .deletePayment(paymentSession) - }) - } - /** * Finds a provider given an id * @param {string} providerId - the id of the provider to get @@ -387,26 +353,22 @@ export default class PaymentProviderService extends TransactionBaseService { } } - async createPayment(data: { - cart_id: string - amount: number - currency_code: string - payment_session: PaymentSession - }): Promise { + async createPayment(data: CreatePaymentInput): Promise { return await this.atomicPhase_(async (transactionManager) => { - const { payment_session: paymentSession, currency_code, amount } = data + const { payment_session, currency_code, amount, provider_id } = data + const providerId = provider_id ?? payment_session.provider_id - const provider = this.retrieveProvider(paymentSession.provider_id) + const provider = this.retrieveProvider(providerId) const paymentData = await provider .withTransaction(transactionManager) - .getPaymentData(paymentSession) + .getPaymentData(payment_session) const paymentRepo = transactionManager.getCustomRepository( this.paymentRepository_ ) const created = paymentRepo.create({ - provider_id: paymentSession.provider_id, + provider_id: providerId, amount, currency_code, data: paymentData, @@ -417,30 +379,6 @@ export default class PaymentProviderService extends TransactionBaseService { }) } - async createPaymentNew( - paymentInput: Omit & { - payment_session: PaymentSession - } - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const { payment_session, currency_code, amount, provider_id } = - paymentInput - - const provider = this.retrieveProvider(provider_id) - const paymentData = await provider - .withTransaction(transactionManager) - .getPaymentData(payment_session) - - const paymentService = this.container_.paymentService - return await paymentService.withTransaction(transactionManager).create({ - provider_id, - amount, - currency_code, - data: paymentData, - }) - }) - } - async updatePayment( paymentId: string, data: { order_id?: string; swap_id?: string } @@ -696,4 +634,123 @@ export default class PaymentProviderService extends TransactionBaseService { return refund } + + /** + * Build the create session context for both legacy and new API + * @param cartOrData + * @protected + */ + protected buildPaymentContext( + cartOrData: Cart | PaymentSessionInput + ): Cart & PaymentContext { + const cart = + "object" in cartOrData && cartOrData.object === "cart" + ? cartOrData + : ((cartOrData as PaymentSessionInput).cart as Cart) + + const context = {} as Cart & PaymentContext + + // TODO: only to support legacy API. Once we are ready to break the API, the cartOrData will only support PaymentSessionInput + if ("object" in cartOrData && cartOrData.object === "cart") { + context.cart = { + context: cart.context, + shipping_address: cart.shipping_address, + id: cart.id, + email: cart.email, + shipping_methods: cart.shipping_methods, + } + context.amount = cart.total! + context.currency_code = cart.region?.currency_code + Object.assign(context, cart) + } else { + const data = cartOrData as PaymentSessionInput + context.cart = data.cart + context.amount = data.amount + context.currency_code = data.currency_code + Object.assign(context, cart) + } + + return context + } + + /** + * Create or update a Payment session data. + * @param providerId + * @param data + * @protected + */ + protected async saveSession( + providerId: string, + data: { + payment_session_id?: string + cartId?: string + amount?: number + sessionData: Record + isSelected?: boolean + status?: PaymentSessionStatus + } + ): Promise { + const manager = this.transactionManager_ ?? this.manager_ + + if ( + data.amount != null && + !this.featureFlagRouter_.isFeatureEnabled(OrderEditingFeatureFlag.key) + ) { + throw new MedusaError( + MedusaError.Types.INVALID_ARGUMENT, + "Amount on payment sessions is only available with the OrderEditing API currently guarded by feature flag `MEDUSA_FF_ORDER_EDITING`. Read more about feature flags here: https://docs.medusajs.com/advanced/backend/feature-flags/toggle/" + ) + } + + const sessionRepo = manager.getCustomRepository( + this.paymentSessionRepository_ + ) + + if (data.payment_session_id) { + const session = await this.retrieveSession(data.payment_session_id) + session.data = data.sessionData ?? session.data + session.status = data.status ?? session.status + session.amount = data.amount ?? session.amount + return await sessionRepo.save(session) + } else { + const toCreate: Partial = { + cart_id: data.cartId || null, + provider_id: providerId, + data: data.sessionData, + is_selected: data.isSelected, + status: data.status, + amount: data.amount, + } + + const created = sessionRepo.create(toCreate) + return await sessionRepo.save(created) + } + } + + /** + * Process the collected data. Can be used every time we need to process some collected data returned by the provider + * @param data + * @param paymentResponse + * @protected + */ + protected async processUpdateRequestsData( + data: { customer?: { id?: string } } = {}, + paymentResponse: PaymentSessionResponse | Record + ): Promise { + const { update_requests } = paymentResponse as PaymentSessionResponse + + if (!update_requests) { + return + } + + const manager = this.transactionManager_ ?? this.manager_ + + if (update_requests.customer_metadata && data.customer?.id) { + await this.customerService_ + .withTransaction(manager) + .update(data.customer.id, { + metadata: update_requests.customer_metadata, + }) + } + } } diff --git a/packages/medusa/src/services/payment.ts b/packages/medusa/src/services/payment.ts index ae8a6220a9..5c5b1473e6 100644 --- a/packages/medusa/src/services/payment.ts +++ b/packages/medusa/src/services/payment.ts @@ -1,11 +1,11 @@ import { PaymentRepository } from "./../repositories/payment" import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Payment, Refund } from "../models" import { TransactionBaseService } from "../interfaces" import { EventBusService, PaymentProviderService } from "./index" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import { FindConfig } from "../types/common" type InjectedDependencies = { diff --git a/packages/medusa/src/services/price-list.ts b/packages/medusa/src/services/price-list.ts index f353f201d3..8dca976944 100644 --- a/packages/medusa/src/services/price-list.ts +++ b/packages/medusa/src/services/price-list.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager, FindOperator } from "typeorm" import { CustomerGroupService } from "." import { CustomerGroup, PriceList, Product, ProductVariant } from "../models" @@ -18,7 +18,7 @@ import { import ProductService from "./product" import RegionService from "./region" import { TransactionBaseService } from "../interfaces" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" import { FilterableProductProps } from "../types/product" import ProductVariantService from "./product-variant" import { FilterableProductVariantProps } from "../types/product-variant" diff --git a/packages/medusa/src/services/product-collection.ts b/packages/medusa/src/services/product-collection.ts index e4eccb70a8..a34a3668ae 100644 --- a/packages/medusa/src/services/product-collection.ts +++ b/packages/medusa/src/services/product-collection.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Brackets, EntityManager, ILike } from "typeorm" import { TransactionBaseService } from "../interfaces" import { ProductCollection } from "../models" @@ -9,7 +9,7 @@ import { CreateProductCollection, UpdateProductCollection, } from "../types/product-collection" -import { buildQuery, isDefined, isString, setMetadata } from "../utils" +import { buildQuery, isString, setMetadata } from "../utils" import EventBusService from "./event-bus" type InjectedDependencies = { diff --git a/packages/medusa/src/services/product-variant.ts b/packages/medusa/src/services/product-variant.ts index 5f8ab27ac4..4e29b3c04a 100644 --- a/packages/medusa/src/services/product-variant.ts +++ b/packages/medusa/src/services/product-variant.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { Brackets, EntityManager, ILike, SelectQueryBuilder } from "typeorm" import { IPriceSelectionStrategy, @@ -29,7 +29,7 @@ import { ProductVariantPrice, UpdateProductVariantInput, } from "../types/product-variant" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" class ProductVariantService extends TransactionBaseService { static Events = { diff --git a/packages/medusa/src/services/product.ts b/packages/medusa/src/services/product.ts index ae6f232c00..a5423d5f1b 100644 --- a/packages/medusa/src/services/product.ts +++ b/packages/medusa/src/services/product.ts @@ -1,6 +1,6 @@ import { FlagRouter } from "../utils/flag-router" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { ProductVariantService, SearchService } from "." import { TransactionBaseService } from "../interfaces" @@ -31,7 +31,7 @@ import { ProductSelector, UpdateProductInput, } from "../types/product" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import EventBusService from "./event-bus" type InjectedDependencies = { diff --git a/packages/medusa/src/services/publishable-api-key.ts b/packages/medusa/src/services/publishable-api-key.ts index 584d24da23..f0ac4d7dd3 100644 --- a/packages/medusa/src/services/publishable-api-key.ts +++ b/packages/medusa/src/services/publishable-api-key.ts @@ -1,12 +1,12 @@ import { EntityManager, ILike } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { PublishableApiKeyRepository } from "../repositories/publishable-api-key" import { FindConfig, Selector } from "../types/common" import { PublishableApiKey, SalesChannel } from "../models" import { TransactionBaseService } from "../interfaces" import EventBusService from "./event-bus" -import { buildQuery, isDefined, isString } from "../utils" +import { buildQuery, isString } from "../utils" import { CreatePublishableApiKeyInput, UpdatePublishableApiKeyInput, diff --git a/packages/medusa/src/services/region.ts b/packages/medusa/src/services/region.ts index 90119eb163..40aad7c70d 100644 --- a/packages/medusa/src/services/region.ts +++ b/packages/medusa/src/services/region.ts @@ -1,6 +1,6 @@ import { DeepPartial, EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { TransactionBaseService } from "../interfaces" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" @@ -13,7 +13,7 @@ import { RegionRepository } from "../repositories/region" import { TaxProviderRepository } from "../repositories/tax-provider" import { FindConfig, Selector } from "../types/common" import { CreateRegionInput, UpdateRegionInput } from "../types/region" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { countries } from "../utils/countries" import { FlagRouter } from "../utils/flag-router" import EventBusService from "./event-bus" diff --git a/packages/medusa/src/services/return-reason.ts b/packages/medusa/src/services/return-reason.ts index b1ff1fbf5f..a00e9c904c 100644 --- a/packages/medusa/src/services/return-reason.ts +++ b/packages/medusa/src/services/return-reason.ts @@ -1,11 +1,11 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" -import { Return, ReturnReason } from "../models" +import { ReturnReason } from "../models" import { ReturnReasonRepository } from "../repositories/return-reason" import { FindConfig, Selector } from "../types/common" import { CreateReturnReason, UpdateReturnReason } from "../types/return-reason" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" type InjectedDependencies = { manager: EntityManager diff --git a/packages/medusa/src/services/return.ts b/packages/medusa/src/services/return.ts index 959bd76733..3f90eb90f2 100644 --- a/packages/medusa/src/services/return.ts +++ b/packages/medusa/src/services/return.ts @@ -1,5 +1,4 @@ -import { isDefined } from "class-validator" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { diff --git a/packages/medusa/src/services/sales-channel.ts b/packages/medusa/src/services/sales-channel.ts index 1bae7f4474..d25c71cbfe 100644 --- a/packages/medusa/src/services/sales-channel.ts +++ b/packages/medusa/src/services/sales-channel.ts @@ -6,12 +6,12 @@ import { FindConfig, QuerySelector, Selector } from "../types/common" import { EntityManager } from "typeorm" import EventBusService from "./event-bus" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { SalesChannel } from "../models" import { SalesChannelRepository } from "../repositories/sales-channel" import StoreService from "./store" import { TransactionBaseService } from "../interfaces" -import { buildQuery, isDefined } from "../utils" +import { buildQuery } from "../utils" type InjectedDependencies = { salesChannelRepository: typeof SalesChannelRepository diff --git a/packages/medusa/src/services/shipping-option.ts b/packages/medusa/src/services/shipping-option.ts index 4982372c64..c674ac6dd9 100644 --- a/packages/medusa/src/services/shipping-option.ts +++ b/packages/medusa/src/services/shipping-option.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" @@ -21,7 +21,7 @@ import { UpdateShippingOptionInput, ValidatePriceTypeAndAmountInput, } from "../types/shipping-options" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { FlagRouter } from "../utils/flag-router" import FulfillmentProviderService from "./fulfillment-provider" import RegionService from "./region" diff --git a/packages/medusa/src/services/shipping-profile.ts b/packages/medusa/src/services/shipping-profile.ts index 518e0207f0..49a34192c9 100644 --- a/packages/medusa/src/services/shipping-profile.ts +++ b/packages/medusa/src/services/shipping-profile.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" import { @@ -15,7 +15,7 @@ import { CreateShippingProfile, UpdateShippingProfile, } from "../types/shipping-profile" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import CustomShippingOptionService from "./custom-shipping-option" import ProductService from "./product" import ShippingOptionService from "./shipping-option" diff --git a/packages/medusa/src/services/swap.ts b/packages/medusa/src/services/swap.ts index 2a36d9f8d2..6caf4eb527 100644 --- a/packages/medusa/src/services/swap.ts +++ b/packages/medusa/src/services/swap.ts @@ -1,7 +1,7 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" -import { buildQuery, isDefined, setMetadata, validateId } from "../utils" +import { buildQuery, setMetadata, validateId } from "../utils" import { TransactionBaseService } from "../interfaces" import LineItemAdjustmentService from "./line-item-adjustment" diff --git a/packages/medusa/src/services/tax-rate.ts b/packages/medusa/src/services/tax-rate.ts index 3ce370329b..272b6ab82c 100644 --- a/packages/medusa/src/services/tax-rate.ts +++ b/packages/medusa/src/services/tax-rate.ts @@ -1,9 +1,11 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" -import { ProductTaxRate } from "../models/product-tax-rate" -import { ProductTypeTaxRate } from "../models/product-type-tax-rate" -import { ShippingTaxRate } from "../models/shipping-tax-rate" -import { TaxRate } from "../models/tax-rate" +import { + ProductTaxRate, + ProductTypeTaxRate, + ShippingTaxRate, + TaxRate, +} from "../models" import { TaxRateRepository } from "../repositories/tax-rate" import ProductService from "../services/product" import ProductTypeService from "../services/product-type" @@ -15,7 +17,7 @@ import { TaxRateListByConfig, UpdateTaxRateInput, } from "../types/tax-rate" -import { buildQuery, isDefined, PostgresError } from "../utils" +import { buildQuery, PostgresError } from "../utils" import { TransactionBaseService } from "../interfaces" import { FindConditions } from "typeorm/find-options/FindConditions" diff --git a/packages/medusa/src/services/totals.ts b/packages/medusa/src/services/totals.ts index 524225ca64..2433404ffd 100644 --- a/packages/medusa/src/services/totals.ts +++ b/packages/medusa/src/services/totals.ts @@ -1,4 +1,4 @@ -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import { ITaxCalculationStrategy, TaxCalculationContext, @@ -28,7 +28,7 @@ import { import TaxProviderService from "./tax-provider" import { EntityManager } from "typeorm" -import { calculatePriceTaxAmount, isDefined } from "../utils" +import { calculatePriceTaxAmount } from "../utils" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" import { FlagRouter } from "../utils/flag-router" diff --git a/packages/medusa/src/services/user.ts b/packages/medusa/src/services/user.ts index ae9e6a6950..eda257f93a 100644 --- a/packages/medusa/src/services/user.ts +++ b/packages/medusa/src/services/user.ts @@ -1,5 +1,5 @@ import jwt from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" +import { isDefined, MedusaError } from "medusa-core-utils" import Scrypt from "scrypt-kdf" import { EntityManager } from "typeorm" import { TransactionBaseService } from "../interfaces" @@ -12,7 +12,7 @@ import { FilterableUserProps, UpdateUserInput, } from "../types/user" -import { buildQuery, isDefined, setMetadata } from "../utils" +import { buildQuery, setMetadata } from "../utils" import { FlagRouter } from "../utils/flag-router" import { validateEmail } from "../utils/is-email" import AnalyticsConfigService from "./analytics-config" diff --git a/packages/medusa/src/strategies/price-selection.ts b/packages/medusa/src/strategies/price-selection.ts index 490e83f24b..42eb2e8d1e 100644 --- a/packages/medusa/src/strategies/price-selection.ts +++ b/packages/medusa/src/strategies/price-selection.ts @@ -7,11 +7,11 @@ import { PriceSelectionResult, PriceType, } from "../interfaces" +import { isDefined } from "medusa-core-utils" import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" import { MoneyAmountRepository } from "../repositories/money-amount" import { TaxServiceRate } from "../types/tax-service" import { FlagRouter } from "../utils/flag-router" -import { isDefined } from "../utils" class PriceSelectionStrategy extends AbstractPriceSelectionStrategy { protected manager_: EntityManager diff --git a/packages/medusa/src/subscribers/cart.ts b/packages/medusa/src/subscribers/cart.ts new file mode 100644 index 0000000000..36175add11 --- /dev/null +++ b/packages/medusa/src/subscribers/cart.ts @@ -0,0 +1,70 @@ +import EventBusService from "../services/event-bus" +import { CartService, PaymentProviderService } from "../services" +import { EntityManager } from "typeorm" + +type InjectedDependencies = { + eventBusService: EventBusService + cartService: CartService + paymentProviderService: PaymentProviderService + manager: EntityManager +} + +class CartSubscriber { + protected readonly manager_: EntityManager + protected readonly cartService_: CartService + protected readonly paymentProviderService_: PaymentProviderService + protected readonly eventBus_: EventBusService + + constructor({ + manager, + cartService, + paymentProviderService, + eventBusService, + }: InjectedDependencies) { + this.cartService_ = cartService + this.paymentProviderService_ = paymentProviderService + this.eventBus_ = eventBusService + this.manager_ = manager + + this.eventBus_.subscribe( + CartService.Events.CUSTOMER_UPDATED, + async (cartId) => { + await this.onCustomerUpdated(cartId) + } + ) + } + + async onCustomerUpdated(cartId) { + await this.manager_.transaction( + "SERIALIZABLE", + async (transactionManager) => { + const cart = await this.cartService_ + .withTransaction(transactionManager) + .retrieveWithTotals(cartId, { + relations: [ + "billing_address", + "region", + "region.payment_providers", + "payment_sessions", + "customer", + ], + }) + + if (!cart.payment_sessions?.length) { + return + } + + const paymentProviderServiceTx = + this.paymentProviderService_.withTransaction(transactionManager) + + return await Promise.all( + cart.payment_sessions.map(async (paymentSession) => { + return paymentProviderServiceTx.updateSession(paymentSession, cart) + }) + ) + } + ) + } +} + +export default CartSubscriber diff --git a/packages/medusa/src/types/payment-collection.ts b/packages/medusa/src/types/payment-collection.ts index 0463b990c3..6897958ae9 100644 --- a/packages/medusa/src/types/payment-collection.ts +++ b/packages/medusa/src/types/payment-collection.ts @@ -1,9 +1,4 @@ -import { - Cart, - Customer, - PaymentCollection, - PaymentCollectionType, -} from "../models" +import { PaymentCollection, PaymentCollectionType } from "../models" export type CreatePaymentCollectionInput = { region_id: string @@ -25,15 +20,6 @@ export type PaymentCollectionsSessionsInput = { provider_id: string } -export type PaymentProviderDataInput = { - resource_id: string - customer: Partial | null - currency_code: string - provider_id: string - amount: number - cart_id?: string - cart?: Cart -} export const defaultPaymentCollectionRelations = [ "region", "region.payment_providers", diff --git a/packages/medusa/src/types/payment.ts b/packages/medusa/src/types/payment.ts new file mode 100644 index 0000000000..b379672aab --- /dev/null +++ b/packages/medusa/src/types/payment.ts @@ -0,0 +1,34 @@ +import { + Address, + Cart, + Customer, + PaymentSession, + ShippingMethod, +} from "../models" + +export type PaymentSessionInput = { + provider_id: string + // TODO: Support legacy payment provider API> Once we are ready to break the api then we can remove the Cart type + cart: + | Cart + | { + context: Record + id: string + email: string + shipping_address: Address | null + shipping_methods: ShippingMethod[] + } + customer?: Customer | null + currency_code: string + amount: number + resource_id?: string +} + +export type CreatePaymentInput = { + cart_id?: string + amount: number + currency_code: string + provider_id?: string + payment_session: PaymentSession + resource_id?: string +} diff --git a/packages/medusa/src/utils/get-query-config.ts b/packages/medusa/src/utils/get-query-config.ts index 76c83f4776..377ebd2142 100644 --- a/packages/medusa/src/utils/get-query-config.ts +++ b/packages/medusa/src/utils/get-query-config.ts @@ -1,8 +1,7 @@ import { pick } from "lodash" import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common" -import { MedusaError } from "medusa-core-utils/dist" +import { isDefined, MedusaError } from "medusa-core-utils" import { BaseEntity } from "../interfaces" -import { isDefined } from "." export function pickByConfig( obj: TModel | TModel[], diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index f4ae33fe78..398554bac6 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -3,7 +3,6 @@ export * from "./set-metadata" export * from "./validate-id" export * from "./generate-entity-id" export * from "./remove-undefined-properties" -export * from "./is-defined" export * from "./is-string" export * from "./calculate-price-tax-amount" export * from "./csv-cell-content-formatter" diff --git a/packages/medusa/src/utils/remove-undefined-properties.ts b/packages/medusa/src/utils/remove-undefined-properties.ts index cf1c82d060..edc1237419 100644 --- a/packages/medusa/src/utils/remove-undefined-properties.ts +++ b/packages/medusa/src/utils/remove-undefined-properties.ts @@ -1,4 +1,4 @@ -import { isDefined } from "./is-defined" +import { isDefined } from "medusa-core-utils" export function removeUndefinedProperties(inputObj: T): T { const removeProperties = (obj: T) => {