From 809ab2e0eb2d62054481fa6491d3f7cafbadab4f Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Fri, 31 Mar 2023 13:09:57 +0200 Subject: [PATCH] chore: Merge master to develop (#3653) --- .changeset/polite-llamas-sit.md | 5 + .../admin/draft-order/draft-order.js | 9 +- .../__tests__/admin/order-edit/order-edit.js | 5 +- .../api/__tests__/store/cart/cart.js | 25 +++- .../api/__tests__/store/orders.js | 12 +- .../__snapshots__/index.js.snap | 8 ++ .../client-types/src/lib/models/Cart.ts | 6 +- .../client-types/src/lib/models/LineItem.ts | 6 +- .../client-types/src/lib/models/Order.ts | 4 + packages/inventory/CHANGELOG.md | 13 ++ packages/medusa-file-minio/README.md | 86 ++++++++---- packages/medusa-file-s3/README.md | 86 +++++++++--- packages/medusa-file-spaces/README.md | 82 +++++++++-- packages/medusa-fulfillment-manual/README.md | 48 +++++++ .../medusa-fulfillment-webshipper/README.md | 93 ++++++++++--- packages/medusa-payment-adyen/README.md | 79 +++++++++++ packages/medusa-payment-klarna/README.md | 82 +++++++++++ packages/medusa-payment-manual/README.md | 48 +++++++ packages/medusa-payment-paypal/README.md | 86 ++++++++++-- packages/medusa-payment-stripe/README.md | 87 +++++++++--- .../src/api/utils/utils.ts | 10 +- packages/medusa-plugin-algolia/README.md | 103 +++++++++++--- packages/medusa-plugin-brightpearl/README.md | 111 +++++++++++---- packages/medusa-plugin-contentful/README.md | 98 +++++++++++-- .../README.md | 41 ++++++ packages/medusa-plugin-economic/README.md | 84 ++++++++++++ packages/medusa-plugin-ip-lookup/README.md | 54 ++++++++ packages/medusa-plugin-mailchimp/README.md | 81 ++++++++--- packages/medusa-plugin-meilisearch/README.md | 108 ++++++++++++--- .../README.md | 129 ++++++++++-------- packages/medusa-plugin-segment/READMD.md | 15 -- packages/medusa-plugin-segment/README.md | 65 +++++++++ packages/medusa-plugin-sendgrid/README.md | 103 +++++++++----- .../README.md | 75 ++++++++-- packages/medusa-plugin-twilio-sms/README.md | 72 +++++++--- packages/medusa-plugin-wishlist/README.md | 46 +++++++ packages/medusa-source-shopify/README.md | 106 ++++++-------- packages/medusa-test-utils/CHANGELOG.md | 5 + .../medusa-test-utils/src/mock-manager.js | 11 +- .../medusa-test-utils/src/mock-repository.js | 15 +- packages/medusa/CHANGELOG.md | 18 +++ packages/medusa/src/api/middlewares/index.ts | 10 +- .../admin/draft-orders/create-draft-order.ts | 3 +- .../admin/draft-orders/create-line-item.ts | 5 +- .../admin/draft-orders/delete-line-item.ts | 5 +- .../admin/draft-orders/get-draft-order.ts | 5 +- .../admin/draft-orders/register-payment.ts | 5 +- .../admin/draft-orders/update-draft-order.ts | 3 +- .../admin/draft-orders/update-line-item.ts | 5 +- .../admin/orders/add-shipping-method.ts | 3 +- .../api/routes/admin/orders/archive-order.ts | 3 +- .../api/routes/admin/orders/cancel-claim.ts | 3 +- .../admin/orders/cancel-fulfillment-claim.ts | 3 +- .../admin/orders/cancel-fulfillment-swap.ts | 3 +- .../routes/admin/orders/cancel-fulfillment.ts | 3 +- .../api/routes/admin/orders/cancel-order.ts | 3 +- .../api/routes/admin/orders/cancel-swap.ts | 3 +- .../routes/admin/orders/capture-payment.ts | 3 +- .../api/routes/admin/orders/complete-order.ts | 3 +- .../admin/orders/create-claim-shipment.ts | 3 +- .../api/routes/admin/orders/create-claim.ts | 12 +- .../routes/admin/orders/create-fulfillment.ts | 3 +- .../routes/admin/orders/create-shipment.ts | 3 +- .../admin/orders/create-swap-shipment.ts | 3 +- .../api/routes/admin/orders/create-swap.ts | 5 +- .../api/routes/admin/orders/fulfill-claim.ts | 5 +- .../api/routes/admin/orders/fulfill-swap.ts | 5 +- .../src/api/routes/admin/orders/get-order.ts | 4 +- .../src/api/routes/admin/orders/index.ts | 2 +- .../api/routes/admin/orders/list-orders.ts | 11 +- .../admin/orders/process-swap-payment.ts | 3 +- .../api/routes/admin/orders/refund-payment.ts | 3 +- .../api/routes/admin/orders/request-return.ts | 9 +- .../api/routes/admin/orders/update-claim.ts | 3 +- .../api/routes/admin/orders/update-order.ts | 3 +- .../routes/admin/products/update-product.ts | 2 +- .../routes/store/carts/add-shipping-method.ts | 9 +- .../api/routes/store/carts/calculate-taxes.ts | 8 ++ .../api/routes/store/carts/complete-cart.ts | 5 + .../src/api/routes/store/carts/create-cart.ts | 17 +-- .../store/carts/create-line-item/index.ts | 8 ++ .../store/carts/create-payment-sessions.ts | 7 + .../api/routes/store/carts/delete-discount.ts | 3 +- .../routes/store/carts/delete-line-item.ts | 4 +- .../store/carts/delete-payment-session.ts | 3 +- .../src/api/routes/store/carts/get-cart.ts | 3 +- .../src/api/routes/store/carts/index.ts | 83 +++++++++++ .../store/carts/refresh-payment-session.ts | 3 +- .../routes/store/carts/set-payment-session.ts | 9 +- .../src/api/routes/store/carts/update-cart.ts | 3 +- .../routes/store/carts/update-line-item.ts | 9 +- .../store/carts/update-payment-session.ts | 9 +- .../routes/store/orders/get-order-by-cart.ts | 3 +- .../src/api/routes/store/orders/index.ts | 7 + .../routes/store/product-categories/index.ts | 2 +- .../src/api/routes/store/products/index.ts | 6 +- packages/medusa/src/helpers/test-request.js | 14 +- .../interfaces/cart-completion-strategy.ts | 4 +- ...8093365812-line-item-adjustments-amount.ts | 15 ++ packages/medusa/src/models/cart.ts | 5 + .../medusa/src/models/line-item-adjustment.ts | 7 +- packages/medusa/src/models/line-item.ts | 8 +- packages/medusa/src/models/order.ts | 7 +- packages/medusa/src/repositories/image.ts | 4 +- .../medusa/src/repositories/money-amount.ts | 2 +- .../medusa/src/repositories/staged-job.ts | 1 + .../medusa/src/services/__tests__/discount.js | 5 +- .../medusa/src/services/__tests__/order.js | 2 + packages/medusa/src/services/cart.ts | 6 +- packages/medusa/src/services/discount.ts | 12 +- packages/medusa/src/services/new-totals.ts | 12 +- packages/medusa/src/services/order.ts | 6 +- .../medusa/src/services/product-variant.ts | 2 +- packages/medusa/src/services/product.ts | 3 - packages/medusa/src/services/totals.ts | 13 +- .../src/utils/__tests__/omit-deep.spec.ts | 59 ++++++++ .../medusa/src/utils/clean-response-data.ts | 25 +++- packages/medusa/src/utils/index.ts | 4 +- packages/medusa/src/utils/is-object.ts | 4 +- packages/medusa/src/utils/omit-deep.ts | 34 +++++ 120 files changed, 2240 insertions(+), 585 deletions(-) create mode 100644 .changeset/polite-llamas-sit.md create mode 100644 packages/medusa-fulfillment-manual/README.md create mode 100644 packages/medusa-payment-adyen/README.md create mode 100644 packages/medusa-payment-klarna/README.md create mode 100644 packages/medusa-payment-manual/README.md create mode 100644 packages/medusa-plugin-discount-generator/README.md create mode 100644 packages/medusa-plugin-economic/README.md create mode 100644 packages/medusa-plugin-ip-lookup/README.md delete mode 100644 packages/medusa-plugin-segment/READMD.md create mode 100644 packages/medusa-plugin-segment/README.md create mode 100644 packages/medusa-plugin-wishlist/README.md create mode 100644 packages/medusa/src/migrations/1678093365812-line-item-adjustments-amount.ts create mode 100644 packages/medusa/src/utils/__tests__/omit-deep.spec.ts create mode 100644 packages/medusa/src/utils/omit-deep.ts diff --git a/.changeset/polite-llamas-sit.md b/.changeset/polite-llamas-sit.md new file mode 100644 index 0000000000..93c7e283c5 --- /dev/null +++ b/.changeset/polite-llamas-sit.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa): Rounding issues on line item adjustments diff --git a/integration-tests/api/__tests__/admin/draft-order/draft-order.js b/integration-tests/api/__tests__/admin/draft-order/draft-order.js index 4e290d7cb9..18cf678659 100644 --- a/integration-tests/api/__tests__/admin/draft-order/draft-order.js +++ b/integration-tests/api/__tests__/admin/draft-order/draft-order.js @@ -572,11 +572,10 @@ describe("/admin/draft-orders", () => { (item) => item.variant_id === testVariant2Id ) - const lineItem1WeightInTotal = 0.444 // line item amount / amount - const lineItem2WeightInTotal = 0.556 // line item amount / amount - expect(draftOrder.cart.items).toHaveLength(2) + expect(lineItem1.adjustments).toHaveLength(1) + expect(lineItem1.adjustments[0].amount).toBeCloseTo(444, 0) // discountAmount * (line item amount / amount) = 444.4444444444 expect(lineItem1).toEqual( expect.objectContaining({ variant_id: testVariantId, @@ -585,7 +584,6 @@ describe("/admin/draft-orders", () => { adjustments: expect.arrayContaining([ expect.objectContaining({ item_id: lineItem1.id, - amount: discountAmount * lineItem1WeightInTotal, description: "discount", discount_id: discount.id, }), @@ -593,6 +591,8 @@ describe("/admin/draft-orders", () => { }) ) + expect(lineItem2.adjustments).toHaveLength(1) + expect(lineItem2.adjustments[0].amount).toBeCloseTo(556, 0) // discountAmount * (line item amount / amount) = 555.5555555555 expect(lineItem2).toEqual( expect.objectContaining({ variant_id: testVariant2Id, @@ -601,7 +601,6 @@ describe("/admin/draft-orders", () => { adjustments: expect.arrayContaining([ expect.objectContaining({ item_id: lineItem2.id, - amount: discountAmount * lineItem2WeightInTotal, description: "discount", discount_id: discount.id, }), diff --git a/integration-tests/api/__tests__/admin/order-edit/order-edit.js b/integration-tests/api/__tests__/admin/order-edit/order-edit.js index 59f1ecf4ed..716e9779ad 100644 --- a/integration-tests/api/__tests__/admin/order-edit/order-edit.js +++ b/integration-tests/api/__tests__/admin/order-edit/order-edit.js @@ -2482,6 +2482,9 @@ describe("/admin/order-edits", () => { ) expect(item2.adjustments).toHaveLength(1) + expect(item1.adjustments[0].amount).toBeCloseTo(1333, 0) + expect(item2.adjustments[0].amount).toBeCloseTo(667, 0) + expect(response.data.order_edit).toEqual( expect.objectContaining({ id: orderEditId, @@ -2531,7 +2534,6 @@ describe("/admin/order-edits", () => { adjustments: expect.arrayContaining([ expect.objectContaining({ discount_id: discount.id, - amount: 1333, }), ]), }), @@ -2564,7 +2566,6 @@ describe("/admin/order-edits", () => { adjustments: expect.arrayContaining([ expect.objectContaining({ discount_id: discount.id, - amount: 667, }), ]), }), diff --git a/integration-tests/api/__tests__/store/cart/cart.js b/integration-tests/api/__tests__/store/cart/cart.js index 2c4bdc8fb8..a28dfbf06c 100644 --- a/integration-tests/api/__tests__/store/cart/cart.js +++ b/integration-tests/api/__tests__/store/cart/cart.js @@ -604,13 +604,22 @@ describe("/store/carts", () => { .catch((err) => console.log(err)) expect(response.data.cart.items.length).toEqual(2) + + const item1 = response.data.cart.items.find((i) => i.id === "test-li") + expect(item1.adjustments).toHaveLength(1) + + const item2 = response.data.cart.items.find((i) => i.id !== "test-li") + expect(item2.adjustments).toHaveLength(1) + + expect(item1.adjustments[0].amount).toBeCloseTo(17, 0) + expect(item2.adjustments[0].amount).toBeCloseTo(168, 0) + expect(response.data.cart.items).toEqual( expect.arrayContaining([ expect.objectContaining({ adjustments: [ expect.objectContaining({ item_id: "test-li", - amount: 17, discount_id: "medusa-185", }), ], @@ -618,7 +627,6 @@ describe("/store/carts", () => { expect.objectContaining({ adjustments: [ expect.objectContaining({ - amount: 168, discount_id: "medusa-185", }), ], @@ -663,14 +671,23 @@ describe("/store/carts", () => { .catch((err) => console.log(err)) expect(response.data.cart.items.length).toEqual(2) + + const item1 = response.data.cart.items.find((i) => i.id === "test-li") + expect(item1.adjustments).toHaveLength(1) + + const item2 = response.data.cart.items.find( + (i) => i.id === "line-item-2" + ) + expect(item2.adjustments).toHaveLength(1) + expect(response.data.cart.items).toEqual( expect.arrayContaining([ expect.objectContaining({ adjustments: [ expect.objectContaining({ item_id: "test-li", + amount: 9.25, discount_id: "medusa-185", - amount: 9, }), ], }), @@ -678,7 +695,7 @@ describe("/store/carts", () => { adjustments: [ expect.objectContaining({ item_id: "line-item-2", - amount: 176, + amount: 175.75, discount_id: "medusa-185", }), ], diff --git a/integration-tests/api/__tests__/store/orders.js b/integration-tests/api/__tests__/store/orders.js index 5a7127534e..683d346331 100644 --- a/integration-tests/api/__tests__/store/orders.js +++ b/integration-tests/api/__tests__/store/orders.js @@ -168,6 +168,7 @@ describe("/store/carts", () => { // fields "status", "email", + // relations "shipping_address", "fulfillments", @@ -177,7 +178,8 @@ describe("/store/carts", () => { "customer", "payments", "region", - // default + + // totals "shipping_total", "discount_total", "tax_total", @@ -199,6 +201,7 @@ describe("/store/carts", () => { expect(Object.keys(response.data.order)).toEqual([ // fields "status", + // default relations "shipping_address", "fulfillments", @@ -208,7 +211,8 @@ describe("/store/carts", () => { "customer", "payments", "region", - // default + + // totals "shipping_total", "discount_total", "tax_total", @@ -232,9 +236,11 @@ describe("/store/carts", () => { expect(Object.keys(response.data.order)).toEqual([ // fields "status", + // selected relations "billing_address", - // default + + // totals "shipping_total", "discount_total", "tax_total", diff --git a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap index 6774ac9f14..28206c6257 100644 --- a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap +++ b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap @@ -342,6 +342,7 @@ Object { "original_tax_total": 200, "original_total": 1200, "quantity": 1, + "raw_discount_total": 0, "subtotal": 1000, "tax_lines": Array [ Object { @@ -457,6 +458,7 @@ Object { "original_tax_total": 400, "original_total": 2400, "quantity": 2, + "raw_discount_total": 0, "returned_quantity": 1, "shipped_quantity": 2, "should_merge": true, @@ -809,6 +811,7 @@ Object { "original_total": 2400, "price": "10.00 USD", "quantity": 2, + "raw_discount_total": 0, "returned_quantity": null, "shipped_quantity": null, "should_merge": true, @@ -1043,6 +1046,7 @@ Object { "original_total": 2400, "price": "12.00 USD", "quantity": 2, + "raw_discount_total": 0, "returned_quantity": null, "shipped_quantity": 2, "should_merge": true, @@ -1069,6 +1073,7 @@ Object { "original_tax_total": 400, "original_total": 2400, "quantity": 2, + "raw_discount_total": 0, "subtotal": 2000, "tax_lines": Array [ Object { @@ -1320,6 +1325,7 @@ Object { "original_tax_total": 400, "original_total": 2400, "quantity": 2, + "raw_discount_total": 0, "returned_quantity": null, "shipped_quantity": 2, "should_merge": true, @@ -1539,6 +1545,7 @@ Object { "original_tax_total": 200, "original_total": 1200, "quantity": 1, + "raw_discount_total": 0, "subtotal": 1000, "tax_lines": Array [ Object { @@ -1654,6 +1661,7 @@ Object { "original_tax_total": 400, "original_total": 2400, "quantity": 2, + "raw_discount_total": 0, "returned_quantity": null, "shipped_quantity": 2, "should_merge": true, diff --git a/packages/generated/client-types/src/lib/models/Cart.ts b/packages/generated/client-types/src/lib/models/Cart.ts index 08d799df85..9e0b0f657e 100644 --- a/packages/generated/client-types/src/lib/models/Cart.ts +++ b/packages/generated/client-types/src/lib/models/Cart.ts @@ -139,9 +139,13 @@ export interface Cart { */ shipping_total?: number /** - * The total of discount + * The total of discount rounded */ discount_total?: number + /** + * The total of discount + */ + raw_discount_total?: number /** * The total of items with taxes */ diff --git a/packages/generated/client-types/src/lib/models/LineItem.ts b/packages/generated/client-types/src/lib/models/LineItem.ts index d46fac94a8..9cf620b78b 100644 --- a/packages/generated/client-types/src/lib/models/LineItem.ts +++ b/packages/generated/client-types/src/lib/models/LineItem.ts @@ -157,9 +157,13 @@ export interface LineItem { */ original_tax_total?: number /** - * The total of discount of the line item + * The total of discount of the line item rounded */ discount_total?: number + /** + * The total of discount of the line item + */ + raw_discount_total?: number /** * The total of the gift card of the line item */ diff --git a/packages/generated/client-types/src/lib/models/Order.ts b/packages/generated/client-types/src/lib/models/Order.ts index 6d04ca189a..e045e70e0b 100644 --- a/packages/generated/client-types/src/lib/models/Order.ts +++ b/packages/generated/client-types/src/lib/models/Order.ts @@ -206,6 +206,10 @@ export interface Order { /** * The total of discount */ + raw_discount_total?: number + /** + * The total of discount rounded + */ discount_total?: number /** * The total of tax diff --git a/packages/inventory/CHANGELOG.md b/packages/inventory/CHANGELOG.md index 38e7e272a2..5dffeb2087 100644 --- a/packages/inventory/CHANGELOG.md +++ b/packages/inventory/CHANGELOG.md @@ -71,6 +71,19 @@ - Updated dependencies [[`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`271844aed`](https://github.com/medusajs/medusa/commit/271844aedbe45c369e188b5d06458dbd6984cd39), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def)]: - @medusajs/utils@0.0.2-rc.0 - @medusajs/modules-sdk@0.1.0-rc.0 +## 1.0.12 + +### Patch Changes + +- Updated dependencies [[`98fe8fd00`](https://github.com/medusajs/medusa/commit/98fe8fd00a1912fde1d2a93b434bda500a213c14), [`2869763ea`](https://github.com/medusajs/medusa/commit/2869763ea9673cf5c5a3aa10b58f61b8e830ce21)]: + - @medusajs/medusa@1.7.15 + +## 1.0.11 + +### Patch Changes + +- Updated dependencies [[`902ed3c0b`](https://github.com/medusajs/medusa/commit/902ed3c0b21cd525d9975e59b7a8120ae5f7a895), [`fa4049cb5`](https://github.com/medusajs/medusa/commit/fa4049cb51232b2ed7091b1322c3fc14cd23e451)]: + - @medusajs/medusa@1.7.14 ## 1.0.10 diff --git a/packages/medusa-file-minio/README.md b/packages/medusa-file-minio/README.md index cd4ab9a8d3..d80dd57605 100644 --- a/packages/medusa-file-minio/README.md +++ b/packages/medusa-file-minio/README.md @@ -1,38 +1,72 @@ -# medusa-file-minio +# MinIO -Upload files to a MinIO server. +Store uploaded files to your Medusa backend on MinIO. -Learn more about how you can use this plugin in the [documentation](https://docs.medusajs.com/add-plugins/minio). +[Plugin Documentation](https://docs.medusajs.com/plugins/file-service/minio) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - endpoint: "minio.server.com", - bucket: "test", - access_key_id: "YOUR-ACCESS-KEY", - secret_access_key: "YOUR-SECRET-KEY", +- Store product images on MinIO +- Support for importing and exporting data through CSV files, such as Products or Prices. +- Support for both private and public buckets. - // private bucket configuration - private_bucket: 'private-bucket', - private_access_key_id: "YOUR-ACCESS-KEY", - private_secret_access_key: "YOUR-SECRET-KEY", -} -``` +--- -Optionally a `download_url_duration` option can be specified to change the valid duration of presigned download links. The duration is configured in seconds. (Default = 60 seconds) +## Prerequisites -## Configuring a private bucket in Minio +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [MinIO](https://docs.min.io/minio/baremetal/quickstart/quickstart.html) -Certain operations in Medusa such as data import and export require a separate, protected bucket. The plugin will raise an error if operations used for imports and exports are invoked without the correct setup. +--- -Configuring Minio for requires configuration of one additional option: `private_bucket` which refers to the name given to the protected bucket in Minio. +## How to Install -Separate credentials can, optionally, be used to access the private bucket by configuring the following options: +1\. Run the following command in the directory of the Medusa backend: -``` - private_access_key_id: "YOUR-ACCESS-KEY", - private_secret_access_key: "YOUR-SECRET-KEY", -``` + ```bash + npm install medusa-file-minio + ``` -If no separate access key is given the same access key will be used for both the `bucket` and the `private_bucket`. +2\. Set the following environment variables in `.env`: + + ```bash + MINIO_ENDPOINT= + MINIO_BUCKET= + MINIO_ACCESS_KEY= + MINIO_SECRET_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-file-minio`, + options: { + endpoint: process.env.MINIO_ENDPOINT, + bucket: process.env.MINIO_BUCKET, + access_key_id: process.env.MINIO_ACCESS_KEY, + secret_access_key: process.env.MINIO_SECRET_KEY, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Upload an image for a product using the admin dashboard or using [the Admin APIs](https://docs.medusajs.com/api/admin#tag/Upload). + +--- + +## Additional Resources + +- [MinIO Plugin Documentation](https://docs.medusajs.com/plugins/file-service/minio) \ No newline at end of file diff --git a/packages/medusa-file-s3/README.md b/packages/medusa-file-s3/README.md index 416c362159..c50228a054 100644 --- a/packages/medusa-file-s3/README.md +++ b/packages/medusa-file-s3/README.md @@ -1,20 +1,74 @@ -# medusa-file-s3 +# S3 -Upload files to an AWS S3 bucket. +Store uploaded files to your Medusa backend on S3. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/s3). +[Plugin Documentation](https://docs.medusajs.com/plugins/file-service/s3) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - s3_url: "https://s3-guide-test.s3.eu-west-1.amazonaws.com", - bucket: "test", - region: "eu-west-1" - access_key_id: "YOUR-ACCESS-KEY", - secret_access_key: "YOUR-SECRET-KEY", - aws_config_object : { - // object for aws config properties - } -} -``` +- Store product images on S3 +- Support for importing and exporting data through CSV files, such as Products or Prices. +- Support for Bucket Policies and User Permissions. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [S3](https://aws.amazon.com/s3) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-file-s3 + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + S3_URL= + S3_BUCKET= + S3_REGION= + S3_ACCESS_KEY_ID= + S3_SECRET_ACCESS_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-file-s3`, + options: { + s3_url: process.env.S3_URL, + bucket: process.env.S3_BUCKET, + region: process.env.S3_REGION, + access_key_id: process.env.S3_ACCESS_KEY_ID, + secret_access_key: process.env.S3_SECRET_ACCESS_KEY, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Upload an image for a product using the admin dashboard or using [the Admin APIs](https://docs.medusajs.com/api/admin#tag/Upload). + +--- + +## Additional Resources + +- [S3 Plugin Documentation](https://docs.medusajs.com/plugins/file-service/s3) \ No newline at end of file diff --git a/packages/medusa-file-spaces/README.md b/packages/medusa-file-spaces/README.md index 3c65658f6d..142f502c98 100644 --- a/packages/medusa-file-spaces/README.md +++ b/packages/medusa-file-spaces/README.md @@ -1,19 +1,73 @@ -# medusa-file-spaces +# DigitalOcean Spaces -Upload files to a DigitalOcean Space. +Store uploaded files to your Medusa backend on Spaces. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/spaces). +[Plugin Documentation](https://docs.medusajs.com/plugins/file-service/spaces) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - spaces_url: "https://test.fra1.digitaloceanspaces.com", - bucket: "test", - endpoint: "fra1.digitaloceanspaces.com", - access_key_id: "YOUR-ACCESS-KEY", - secret_access_key: "YOUR-SECRET-KEY", -} -``` +- Store product images on DigitalOcean Spaces +- Support for importing and exporting data through CSV files, such as Products or Prices. -Optionally a `download_url_duration` option can be specified to change the valid duration of presigned download links. The duration is configured in seconds. (Default = 60 seconds) +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-file-spaces + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + SPACE_URL= + SPACE_BUCKET= + SPACE_ENDPOINT= + SPACE_ACCESS_KEY_ID= + SPACE_SECRET_ACCESS_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-file-spaces`, + options: { + spaces_url: process.env.SPACE_URL, + bucket: process.env.SPACE_BUCKET, + endpoint: process.env.SPACE_ENDPOINT, + access_key_id: process.env.SPACE_ACCESS_KEY_ID, + secret_access_key: process.env.SPACE_SECRET_ACCESS_KEY, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Upload an image for a product using the admin dashboard or using [the Admin APIs](https://docs.medusajs.com/api/admin#tag/Upload). + +--- + +## Additional Resources + +- [Spaces Plugin Documentation](https://docs.medusajs.com/plugins/file-service/spaces) \ No newline at end of file diff --git a/packages/medusa-fulfillment-manual/README.md b/packages/medusa-fulfillment-manual/README.md new file mode 100644 index 0000000000..52418fb063 --- /dev/null +++ b/packages/medusa-fulfillment-manual/README.md @@ -0,0 +1,48 @@ +# Manual Fulfillment + +A minimal fulfillment provider that allows merchants to handle fulfillments manually. + +[Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Provides a restriction-free fulfillment provider that can be used during checkout and while processing orders. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-fulfillment-manual + ``` + +2\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + `medusa-fulfillment-manual` + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable the fulfillment provider in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use the manual fulfillment provider during checkout. \ No newline at end of file diff --git a/packages/medusa-fulfillment-webshipper/README.md b/packages/medusa-fulfillment-webshipper/README.md index a5859fbe14..962111c2fb 100644 --- a/packages/medusa-fulfillment-webshipper/README.md +++ b/packages/medusa-fulfillment-webshipper/README.md @@ -1,26 +1,85 @@ -# medusa-fulfillment-webshipper +# Webshipper -Adds Webshipper as a fulfilment provider in Medusa Commerce. +Handle order fulfillments using Webshipper. -On each new fulfillment an order is created in Webshipper. The plugin listens for shipment events and updated the shipment accordingly. -A webhook listener is exposed at `/webshipper/shipments` to listen for shipment creations. You must create this webhook in Webshipper to have Medusa listen for shipment events. +[Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -``` - account: [your webshipper account] (required) - api_token: [a webshipper api token] (required) - order_channel_id: [the channel id to register orders on] (required) - webhook_secret: [the webhook secret used to listen for shipments] (required) - coo_countries: [an array of countries in which a Certificate of Origin will be attached] (default: "all") - delete_on_cancel [determines whether Webshipper orders are deleted when a Medusa fulfillment is canceled] (default: false) -``` +- Webshipper can be used as a shipping option during checkouts and for handling order fulfillment. +- Sync order details and updates with Webshipper. +- Support for Webshipper webhooks. -## Personal Customs Numbers +--- -In countries like South Korea a personal customs number is required to clear customs. The Webshipper fulfillment plugin is able pass this information to Webshipper given that the number is stored in `order.shipping_address.metadata.personal_customs_no`. +## Prerequisites -### Modifications in checkout flow +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Webshipper Account](https://webshipper.com) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-fulfillment-webshipper + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + WEBSHIPPER_ACCOUNT= + WEBSHIPPER_API_TOKEN= + WEBSHIPPER_ORDER_CHANNEL_ID= + WEBSHIPPER_WEBHOOK_SECRET= + WEBSHIPPER_COO_COUNTRIES= + WEBSHIPPER_DELETE_ON_CANCEL= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-fulfillment-webshipper`, + options: { + account: process.env.WEBSHIPPER_ACCOUNT, // required + api_token: process.env.WEBSHIPPER_API_TOKEN, // required + order_channel_id: process.env.WEBSHIPPER_ORDER_CHANNEL_ID, // required, the channel id to register orders on + webhook_secret: process.env.WEBSHIPPER_WEBHOOK_SECRET, // required, the webhook secret used to listen for shipments + coo_countries: process.env.WEBSHIPPER_COO_COUNTRIES, // default: "all", an array of countries or a string of one country in which a Certificate of Origin will be attached + delete_on_cancel: process.env.WEBSHIPPER_DELETE_ON_CANCEL, // default: false, determines whether Webshipper orders are deleted when a Medusa fulfillment is canceled + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable the fulfillment provider in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use the manual fulfillment provider during checkout. + +--- + +## Additional Details + +### Personal Customs Numbers + +In countries like South Korea, a personal customs number is required to clear customs. The Webshipper fulfillment plugin is able pass this information to Webshipper given that the number is stored in `order.shipping_address.metadata.personal_customs_no`. + +#### Modifications in Checkout Flow To pass the information along you should dynamically show an input field to the customer when they are shopping from a region that requires a personal customs number, and make sure that the metadata field is set when updating the cart shipping address. @@ -43,4 +102,4 @@ const onUpdateAddress = async () => { console.log("Good stuff - Webshipper will pass along the customs number") }) } -``` +``` \ No newline at end of file diff --git a/packages/medusa-payment-adyen/README.md b/packages/medusa-payment-adyen/README.md new file mode 100644 index 0000000000..d7996b9bcc --- /dev/null +++ b/packages/medusa-payment-adyen/README.md @@ -0,0 +1,79 @@ +# Adyen + +Receive payments on your Medusa commerce application using Adyen. + +> This plugin is not ready for production use. Community contributions are highly appreciated. You can learn more about contributing in [our repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Authorize payments on orders from any sales channel. +- Support for MobilePay. +- Capture payments from the admin dashboard. +- Support for Webhooks. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Adyen account](https://www.adyen.com) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-payment-adyen + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + ADYEN_API_KEY= + ADYEN_NOTIFICATION_HMAC= + ADYEN_RETURN_URL= + ADYEN_MERCHANT_ACCOUNT= + ADYEN_ORIGIN= + ADYEN_ENVIRONMENT= + ADYEN_LIVE_ENDPOINT_PREFIX= + ADYEN_PAYMENT_ENDPOINT= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-payment-adyen`, + options: { + api_key: process.env.STRIPE_API_KEY, + notification_hmac: process.env.ADYEN_NOTIFICATION_HMAC, + return_url: process.env.ADYEN_RETURN_URL, + merchant_account: process.env.ADYEN_MERCHANT_ACCOUNT, + origin: process.env.ADYEN_ORIGIN, + environment: process.env.ADYEN_ENVIRONMENT, + live_endpoint_prefix: process.env.ADYEN_LIVE_ENDPOINT_PREFIX, + payment_endpoint: process.env.ADYEN_PAYMENT_ENDPOINT, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable Adyen in a region in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use Stripe as a payment method. \ No newline at end of file diff --git a/packages/medusa-payment-klarna/README.md b/packages/medusa-payment-klarna/README.md new file mode 100644 index 0000000000..1f8e6e86e5 --- /dev/null +++ b/packages/medusa-payment-klarna/README.md @@ -0,0 +1,82 @@ +# Klarna + +Receive payments on your Medusa commerce application using Klarna. + +[Klarna Plugin Documentation](https://docs.medusajs.com/plugins/payment/klarna) | [Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Authorize payments on orders from any sales channel. +- Capture payments from the admin dashboard. +- Support for Webhooks. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Klarna account](https://www.klarna.com/) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-payment-klarna + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + KLARNA_BACKEND_URL= + KLARNA_URL= + KLARNA_USER= + KLARNA_PASSWORD= + KLARNA_TERMS_URL= + KLARNA_CHECKOUT_URL= + KLARNA_CONFIRMATION_URL= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // other plugins... + { + resolve: `medusa-payment-klarna`, + options: { + backend_url: process.env.KLARNA_BACKEND_URL, + url: process.env.KLARNA_URL, + user: process.env.KLARNA_USER, + password: process.env.KLARNA_PASSWORD, + merchant_urls: { + terms: process.env.KLARNA_TERMS_URL, + checkout: process.env.KLARNA_CHECKOUT_URL, + confirmation: process.env.KLARNA_CONFIRMATION_URL, + }, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable Klarna in a region in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use Stripe as a payment method. + +--- + +## Additional Resources + +- [Klarna Plugin Documentation](https://docs.medusajs.com/plugins/payment/klarna) \ No newline at end of file diff --git a/packages/medusa-payment-manual/README.md b/packages/medusa-payment-manual/README.md new file mode 100644 index 0000000000..aa0503e792 --- /dev/null +++ b/packages/medusa-payment-manual/README.md @@ -0,0 +1,48 @@ +# Manual Payment + +A minimal payment provider that allows merchants to handle payments manually. + +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Provides a restriction-free payment provider that can be used during checkout and while processing orders. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-payment-manual + ``` + +2\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + `medusa-payment-manual` + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable the payment provider in a region in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use Stripe as a payment method. diff --git a/packages/medusa-payment-paypal/README.md b/packages/medusa-payment-paypal/README.md index 8938a491b4..c0fff03ff5 100644 --- a/packages/medusa-payment-paypal/README.md +++ b/packages/medusa-payment-paypal/README.md @@ -1,20 +1,78 @@ -# medusa-payment-paypal +# PayPal -Add PayPal as a Payment Provider. +Receive payments on your Medusa commerce application using PayPal. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/paypal). +[PayPal Plugin Documentation](https://docs.medusajs.com/plugins/payment/paypal) | [Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +The paypal plugin version `>=1.3.x` requires medusa `>=1.8.x` -```js -{ - sandbox: true, //default false - clientId: "CLIENT_ID", // REQUIRED - clientSecret: "CLIENT_SECRET", // REQUIRED - authWebhookId: "WEBHOOK_ID", //REQUIRED for webhook to work -} -``` +## Features -## Deprecation +- Authorize payments on orders from any sales channel. +- Capture payments from the admin dashboard. +- View payment analytics through PayPal's dashboard. +- Ready-integration with [Medusa's Next.js starter storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). +- Support for Webhooks. -The paypal plugin version `>=1.3.x` requires medusa `>=1.8.x` \ No newline at end of file +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [PayPal account](https://www.paypal.com) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-payment-paypal + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + PAYPAL_SANDBOX=true + PAYPAL_CLIENT_ID= + PAYPAL_CLIENT_SECRET= + PAYPAL_AUTH_WEBHOOK_ID= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-payment-paypal`, + options: { + sandbox: process.env.PAYPAL_SANDBOX, + client_id: process.env.PAYPAL_CLIENT_ID, + client_secret: process.env.PAYPAL_CLIENT_SECRET, + auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable PayPal in a region in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use Stripe as a payment method. + +--- + +## Additional Resources + +- [PayPal Plugin Documentation](https://docs.medusajs.com/plugins/payment/paypal) diff --git a/packages/medusa-payment-stripe/README.md b/packages/medusa-payment-stripe/README.md index c685ca46ab..fff914a06b 100644 --- a/packages/medusa-payment-stripe/README.md +++ b/packages/medusa-payment-stripe/README.md @@ -1,27 +1,76 @@ -# medusa-payment-stripe +# Stripe -Add Stripe as a Payment Provider. +Receive payments on your Medusa commerce application using Stripe. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/stripe). +[Stripe Plugin Documentation](https://docs.medusajs.com/plugins/payment/stripe) | [Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +The stripe plugin version `>=1.2.x` requires medusa `>=1.8.x` -```js -{ - api_key: "STRIPE_API_KEY", - webhook_secret: "STRIPE_WEBHOOK_SECRET", - - // automatic_payment_methods: true, - - // This description will be used if the cart context does not provide one. - // payment_description: "custom description to apply", -} -``` +## Features -## Automatic Payment Methods +- Authorize payments on orders from any sales channel. +- Support for Bancontact, BLIK, giropay, iDEAL, and Przelewy24. +- Capture payments from the admin dashboard. +- View payment analytics through Stripe's dashboard. +- Ready-integration with [Medusa's Next.js starter storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). +- Support for Stripe Webhooks. -If you wish to use [Stripe's automatic payment methods](https://stripe.com/docs/connect/automatic-payment-methods) set the `automatic_payment_methods` flag to true. +--- -## Deprecation +## Prerequisites -The stripe plugin version `>=1.2.x` requires medusa `>=1.8.x` \ No newline at end of file +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Stripe account](https://stripe.com/) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-payment-stripe + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + STRIPE_API_KEY=sk_... + # only necessary for production + STRIPE_WEBHOOK_SECRET=whsec_... + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-payment-stripe`, + options: { + api_key: process.env.STRIPE_API_KEY, + webhook_secret: process.env.STRIPE_WEBHOOK_SECRET, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Enable Stripe in a region in the admin. You can refer to [this User Guide](https://docs.medusajs.com/user-guide/regions/providers) to learn how to do that. Alternatively, you can use the [Admin APIs](https://docs.medusajs.com/api/admin#tag/Region/operation/PostRegionsRegion). + +3\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should be able to use Stripe as a payment method. + +--- + +## Additional Resources + +- [Stripe Plugin Documentation](https://docs.medusajs.com/plugins/payment/stripe) diff --git a/packages/medusa-payment-stripe/src/api/utils/utils.ts b/packages/medusa-payment-stripe/src/api/utils/utils.ts index cb20ef5e23..7c040033af 100644 --- a/packages/medusa-payment-stripe/src/api/utils/utils.ts +++ b/packages/medusa-payment-stripe/src/api/utils/utils.ts @@ -1,13 +1,13 @@ -import { AwilixContainer } from "awilix" -import Stripe from "stripe" import { AbstractCartCompletionStrategy, CartService, IdempotencyKeyService, PostgresError, } from "@medusajs/medusa" -import { EOL } from "os" +import { AwilixContainer } from "awilix" import { MedusaError } from "medusa-core-utils" +import { EOL } from "os" +import Stripe from "stripe" const PAYMENT_PROVIDER_KEY = "pp_stripe" @@ -251,8 +251,8 @@ async function completeCartIfNecessary({ if (response_code !== 200) { throw new MedusaError( MedusaError.Types.UNEXPECTED_STATE, - response_body["message"], - response_body["code"].toString() + response_body["message"] as string, + response_body["code"] as string ) } } diff --git a/packages/medusa-plugin-algolia/README.md b/packages/medusa-plugin-algolia/README.md index 0467c0edd7..c04c1fa5ea 100644 --- a/packages/medusa-plugin-algolia/README.md +++ b/packages/medusa-plugin-algolia/README.md @@ -1,25 +1,86 @@ -# medusa-plugin-algolia +# Algolia -Algolia Plugin for Medusa to search for products. +Provide powerful indexing and searching features in your commerce application with Algolia. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/algolia). +[Algolia Plugin Documentation](https://docs.medusajs.com/plugins/search/algolia) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - applicationId: "someId", - adminApiKey: "someApiKey", - settings: { - [indexName]: [algolia settings passed to algolia's `updateSettings()` method] - // example - products: { - indexSettings: { - searchableAttributes: ["title", "description", "variant_sku", "type_value"], - attributesToRetrieve: ["title", "description", "variant_sku", "type_value"], - } - transformer: (product: Product) => ({ id: product.id }) - } - } -} -``` +- Flexible configurations for specifying searchable and retrievable attributes. +- Ready-integration with [Medusa's Next.js starter storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). +- Utilize Algolia's powerful search functionalities including typo-tolerance, query suggestions, results ranking, and more. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Algolia account](https://www.algolia.com/) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-algolia + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + ALGOLIA_APP_ID= + ALGOLIA_ADMIN_API_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-plugin-algolia`, + options: { + application_id: process.env.ALGOLIA_APP_ID, + admin_api_key: process.env.ALGOLIA_ADMIN_API_KEY, + settings: { + products: { + searchableAttributes: ["title", "description"], + attributesToRetrieve: [ + "id", + "title", + "description", + "handle", + "thumbnail", + "variants", + "variant_sku", + "options", + "collection_title", + "collection_handle", + "images", + ], + }, + }, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Try searching products either using your storefront or using the [Store APIs](https://docs.medusajs.com/api/store#tag/Product/operation/PostProductsSearch). + +--- + +## Additional Resources + +- [Algolia Plugin Documentation](https://docs.medusajs.com/plugins/search/algolia) diff --git a/packages/medusa-plugin-brightpearl/README.md b/packages/medusa-plugin-brightpearl/README.md index f200b6af21..fcb4a797c7 100644 --- a/packages/medusa-plugin-brightpearl/README.md +++ b/packages/medusa-plugin-brightpearl/README.md @@ -1,37 +1,102 @@ -# medusa-plugin-brightpearl +# Brightpearl -Sends orders to Brightpearl, listens for stock movements, handles returns. +Manage and streamline your business processes using Brightpearl. -## Options +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -``` - account: [the Brightpearl account] (required) - channel_id: [channel id to map sales and credits to] (required) - backend_url: [the url where the Medusa server is running, needed for webhooks] (required) - event_owner: [the id of the user who will own goods out events] (required), - warehouse: [the warehouse id to allocate orders from] (required) - default_status_id: [the status id to assign new orders with] (optional: defaults to 1) - swap_status_id: [the status id to assign new swaps] (optional: defaults to 1) - payment_method_code: [the method code to register payments with] (optional: defaults to 1220) - sales_account_code: [nominal code to assign line items to] (optional: defaults to 4000) - shipping_account_code: [nominal code to assign shipping line to] (optional: defaults to 4040) - discount_account_code: [nominal code to use for Discount-type refunds] (optional) - gift_card_account_code: [nominal code to use for gift card products and redeems] (optional: default to 4000) - inventory_sync_cron: [cron pattern for inventory sync, if left out the job will not be created] (default: false) -``` +## Features +- Send and sync orders with Brightpearl. +- Listen for inventory and stock movements in Brightpearl. +- Handle order returns through Brightpearl. -## Orders +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Brightpearl account](https://www.brightpearl.com) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-brightpearl + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + BRIGHTPEARL_ACCOUNT= + BRIGHTPEARL_CHANNEL_ID= + BRIGHTPEARL_BACKEND_URL= + BRIGHTPEARL_EVENT_OWNER= + BRIGHTPEARL_WAREHOUSE= + BRIGHTPEARL_DEFAULT_STATUS_ID= + BRIGHTPEARL_SWAP_STATUS_ID= + BRIGHTPEARL_PAYMENT_METHOD_CODE= + BRIGHTPEARL_SALES_ACCOUNT_CODE= + BRIGHTPEARL_SHIPPING_ACCOUNT_CODE= + BRIGHTPEARL_DISCOUNT_ACCOUNT_CODE= + BRIGHTPEARL_GIFT_CARD_ACCOUNT_CODE= + BRIGHTPEARL_INVENTORY_SYNC_CRON= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-plugin-brightpearl`, + options: { + account: process.env.BRIGHTPEARL_ACCOUNT, // required, the Brightpearl account + channel_id: process.env.BRIGHTPEARL_CHANNEL_ID, // required, channel id to map sales and credits to + backend_url: process.env.BRIGHTPEARL_BACKEND_URL, // required, the url where the Medusa server is running, needed for webhooks + event_owner: process.env.BRIGHTPEARL_EVENT_OWNER, // required, the id of the user who will own goods out events] + warehouse: process.env.BRIGHTPEARL_WAREHOUSE, // required, the warehouse id to allocate orders from + default_status_id: process.env.BRIGHTPEARL_DEFAULT_STATUS_ID, // (optional: defaults to 1), the status id to assign new orders with + swap_status_id: process.env.BRIGHTPEARL_SWAP_STATUS_ID, // (optional: defaults to 1), the status id to assign new swaps] + payment_method_code: process.env.BRIGHTPEARL_PAYMENT_METHOD_CODE, // (optional: defaults to 1220), the method code to register payments with + sales_account_code: process.env.BRIGHTPEARL_SALES_ACCOUNT_CODE, // (optional: defaults to 4000), nominal code to assign line items to + shipping_account_code: process.env.BRIGHTPEARL_SHIPPING_ACCOUNT_CODE, // (optional: defaults to 4040), nominal code to assign shipping line to + discount_account_code: process.env.BRIGHTPEARL_DISCOUNT_ACCOUNT_CODE, // optional, nominal code to use for Discount-type refunds + gift_card_account_code: process.env.BRIGHTPEARL_GIFT_CARD_ACCOUNT_CODE, // (optional: default to 4000), nominal code to use for gift card products and redeems + inventory_sync_cron: process.env.BRIGHTPEARL_INVENTORY_SYNC_CRON, // (default: false), cron pattern for inventory sync, if left out the job will not be created + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. On placing an order, you should see that order appear on Brightpearl. + +--- + +## Additional Information + +### Orders When an order is created in Medusa it will automatically be sent to Brightpearl and allocated there. Once allocated it is up to Brightpearl to figure out how the order is to be fulfilled - the plugin listens for goods out notes and tries to map each of these to a Medusa order, if the matching succeeds Medusa will send the order to the fulfillment provider associated with the shipping method selected by the Customer. When line items on an order are returned the plugin will generate a sales credit in Brightpearl. -## Products +### Products The plugin doesn't automatically create products in Medusa, but listens for inventory changes in Brightpearl. The plugin updates each product variant to reflect the inventory quantity listed in Brightpearl, thereby ensuring that the inventory levels in Medusa are always in sync with Brightpearl. -## OAuth - -The plugin registers an OAuth app in Medusa allowing installation at https://medusa-commerce.com/a/settings/apps. The OAuth tokens are refreshed every hour to prevent unauthorized requests. +### OAuth +The plugin registers an OAuth app in Medusa allowing installation at https://medusa-commerce.com/a/settings/apps. The OAuth tokens are refreshed every hour to prevent unauthorized requests. \ No newline at end of file diff --git a/packages/medusa-plugin-contentful/README.md b/packages/medusa-plugin-contentful/README.md index aace02037c..55b6121f50 100644 --- a/packages/medusa-plugin-contentful/README.md +++ b/packages/medusa-plugin-contentful/README.md @@ -1,15 +1,91 @@ -# medusa-payment-contentful +# Contentful -Integrate Contentful with Medusa for rich CMS functionalities. +Manage the content of your storefront with rich Content Management System (CMS) capabilities using Contentful. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/contentful). +[Contentful Plugin Documentation](https://docs.medusajs.com/plugins/cms/contentful/) | [Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - space_id: "CONTENTFUL_SPACE_ID", - access_token: "CONTENTFUL_ACCESS_TOKEN", - environment: "CONTENTFUL_ENV", -} -``` +- Handle the presentational content of your commerce application using Contentful. +- Two-way sync between Medusa and Contentful, allowing you to manage products details consistently. +- Benefit from Contentful's advanced CMS features such as localization and versioning. + +--- + +## Prerequisites + +- [Contentful account](https://stripe.com/) +- [Medusa CLI Tool](https://docs.medusajs.com/cli/reference#how-to-install-cli-tool) +- [PostgreSQL](https://docs.medusajs.com/development/backend/prepare-environment#postgresql) +- [Redis](https://docs.medusajs.com/development/backend/prepare-environment#redis) + +--- + +## How to Install + +1\. Run the following command to install a new Medusa server configured with Contentful: + + ```bash + medusa new medusa-contentful https://github.com/medusajs/medusa-starter-contentful + ``` + +2\. Change to the newly created directory `medusa-contentful`: + + ```bash + cd medusa-contentful + ``` + +3\. Set the following environment variables in `.env`: + + ```bash + CONTENTFUL_SPACE_ID= + CONTENTFUL_ACCESS_TOKEN= + CONTENTFUL_ENV= + REDIS_URL= + DATABASE_URL= + ``` + +3\. In `medusa-config.js`, enable PostgreSQL and remove the SQLite configurations: + + ```js + module.exports = { + projectConfig: { + // ... + database_url: DATABASE_URL, + database_type: "postgres", + // REMOVE OR COMMENT OUT THE BELOW: + // database_database: "./medusa-db.sql", + // database_type: "sqlite", + }, + } + ``` + +4\. Migrate the content types into Contentful with the following command: + + ```bash + npm run migrate:contentful + ``` + +5\. Seed Contentful with demo content data using the following command: + + ```bash + npm run seed:contentful + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. You can then setup the [Gatsby Contentful Storefront](https://docs.medusajs.com/plugins/cms/contentful/#setup-gatsby-storefront), or connect to Contentful from your own storefront to retrieve content data. + +--- + +## Additional Resources + +- [Contentful Plugin Documentation](https://docs.medusajs.com/plugins/cms/contentful/) diff --git a/packages/medusa-plugin-discount-generator/README.md b/packages/medusa-plugin-discount-generator/README.md new file mode 100644 index 0000000000..372f80df47 --- /dev/null +++ b/packages/medusa-plugin-discount-generator/README.md @@ -0,0 +1,41 @@ +# Discount Generator + +Generate dynamic discount codes in your Medusa backend. + +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Provides a service that can be used to generate a dynamic discount with a random code. +- Provides an endpoint that can be used to generate a dynamic discount with a random code. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-discount-generator + ``` + +2\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + `medusa-plugin-discount-generator` + ] + ``` + +--- + +## Test the Plugin + +Try using the `DiscountGeneratorService` in your code, or using the `/discount-code` endpoint to generate a random discount code. diff --git a/packages/medusa-plugin-economic/README.md b/packages/medusa-plugin-economic/README.md new file mode 100644 index 0000000000..01f0389734 --- /dev/null +++ b/packages/medusa-plugin-economic/README.md @@ -0,0 +1,84 @@ +# e-conomic + +Manage your commerce accounting with e-conomic. + +> This plugin is not ready for production use. Community contributions are highly appreciated. You can learn more about contributing in [our repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Create draft and book e-conomic invoices automatically when an order is placed. +- Provide endpoints to manually trigger booking and creating draft e-comonic invoices. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Visma e-conomic account](https://www.e-conomic.com/developer/connect) +- [Redis](https://docs.medusajs.com/development/backend/prepare-environment#redis) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-economic + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + ECONOMIC_SECRET_TOKEN= + ECONOMIC_AGREEMENT_TOKEN= + ECONOMIC_CUSTOMER_NUMBER_DK= + ECONOMIC_CUSTOMER_NUMBER_EU= + ECONOMIC_CUSTOMER_NUMBER_WORLD= + ECONOMIC_UNIT_NUMBER= + ECONOMIC_PAYMENT_TERMS_NUMBER= + ECONOMIC_LAYOUT_NUMBER= + ECONOMIC_VATZONE_NUMBER_DK= + ECONOMIC_VATZONE_NUMBER_EU= + ECONOMIC_VATZONE_NUMBER_WORLD= + ECONOMIC_RECIPIENT_NAME= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // other plugins... + { + resolve: `medusa-plugin-economic`, + options: { + secret_token: process.env.ECONOMIC_SECRET_TOKEN, + agreement_token: process.env.ECONOMIC_AGREEMENT_TOKEN, + customer_number_dk: process.env.ECONOMIC_CUSTOMER_NUMBER_DK, + customer_number_eu: process.env.ECONOMIC_CUSTOMER_NUMBER_EU, + customer_number_world: process.env.ECONOMIC_CUSTOMER_NUMBER_WORLD, + unit_number: process.env.ECONOMIC_UNIT_NUMBER, + payment_terms_number: process.env.ECONOMIC_PAYMENT_TERMS_NUMBER, + layout_number: process.env.ECONOMIC_LAYOUT_NUMBER, + vatzone_number_dk: process.env.ECONOMIC_VATZONE_NUMBER_DK, + vatzone_number_eu: process.env.ECONOMIC_VATZONE_NUMBER_EU, + vatzone_number_world: process.env.ECONOMIC_VATZONE_NUMBER_WORLD, + recipient_name: process.env.ECONOMIC_RECIPIENT_NAME, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Try creating an order using the storefront or the [Store APIs](https://docs.medusajs.com/api/store#tag/Cart). Once the order is placed, a draft invoice will be created in e-conomic. diff --git a/packages/medusa-plugin-ip-lookup/README.md b/packages/medusa-plugin-ip-lookup/README.md new file mode 100644 index 0000000000..af08bd54eb --- /dev/null +++ b/packages/medusa-plugin-ip-lookup/README.md @@ -0,0 +1,54 @@ +# ipstack (IP Lookup) + +Automatically detect the region and location of your customer using ipstack. + +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Look up the location of your customer using ipstack. +- Provides a middleware that can be added to any request to set the region and country of a cart. +- Provides a service that can be used across codebase to detect the location of a user using their IP. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [ipstack account](https://ipstack.com) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-ip-lookup + ``` + +2\. Set the following environment variable in `.env`: + + ```bash + IPSTACK_ACCESS_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // other plugins... + { + resolve: `medusa-plugin-ip-lookup`, + options: { + access_token: process.env.IPSTACK_ACCESS_KEY, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +You can use the `IpLookupService` service to look up the location of an IP, or use the middleware `preCartCreation` on any route. diff --git a/packages/medusa-plugin-mailchimp/README.md b/packages/medusa-plugin-mailchimp/README.md index 7dbb50e162..33be13d740 100644 --- a/packages/medusa-plugin-mailchimp/README.md +++ b/packages/medusa-plugin-mailchimp/README.md @@ -1,29 +1,68 @@ -# medusa-plugin-mailchimp +# Mailchimp -Mailchimp plugin for Medusa that supports newsletter subscriptions. +Manage newsletter subscriptions in your commerce application with Mailchimp. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/mailchimp). +[Mailchimp Plugin Documentation](https://docs.medusajs.com/plugins/notifications/mailchimp) | [Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - api_key: "MAILCHIMP_API_KEY", - newsletter_list_id: ["123456789"] -} -``` +- Allow customers to subscribe to your newsletter. +- Provides custom services and endpoints to give developers flexibility in how to implement newsletter subscription. -## Dynamic usage +--- -You can resolve the Mailchimp service, such that your server can handle newsletter subscriptions. +## Prerequisites -Example: +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Mailchimp account](https://mailchimp.com/signup) -```js -const mailchimpService = req.scope.resolve("mailchimpService") -mailchimpService.subscribeNewsletter( - "acme@mail.com", - // merge_fields to include in the subscription - { FIRSTNAME: "Acme", LASTNAME: "Inc." } -) -``` +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-mailchimp + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + MAILCHIMP_API_KEY= + MAILCHIMP_NEWSLETTER_LIST_ID= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ..., + { + resolve: `medusa-plugin-mailchimp`, + options: { + api_key: process.env.MAILCHIMP_API_KEY, + newsletter_list_id: + process.env.MAILCHIMP_NEWSLETTER_LIST_ID, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Use the `/mailchimp/subscribe` endpoint or the `MailchimpService` to subscribe to the newsletter. + +--- + +## Additional Resources + +- [Mailchimp Plugin Documentation](https://docs.medusajs.com/plugins/notifications/mailchimp) diff --git a/packages/medusa-plugin-meilisearch/README.md b/packages/medusa-plugin-meilisearch/README.md index 770613ba94..fdcc6b056e 100644 --- a/packages/medusa-plugin-meilisearch/README.md +++ b/packages/medusa-plugin-meilisearch/README.md @@ -1,27 +1,91 @@ -# medusa-plugin-meilisearch +# MeiliSearch -Meilisearch Plugin for Medusa to search for products. +Provide powerful indexing and searching features in your commerce application with MeiliSearch. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/meilisearch). +[MeiliSearch Plugin Documentation](https://docs.medusajs.com/plugins/search/meilisearch) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - config: { - host: "[your meilisearch host]", - }, - settings: { - "[indexName]": "[meilisearch settings passed to meilisearch's `updateSettings()` method]" - // example - products: { - indexSettings: { - searchableAttributes: ["title", "description", "variant_sku"], - displayedAttributes: ["title", "description", "variant_sku", "thumbnail", "handle"], +- Flexible configurations for specifying searchable and retrievable attributes. +- Ready-integration with [Medusa's Next.js starter storefront](https://docs.medusajs.com/starters/nextjs-medusa-starter). +- Utilize MeiliSearch's powerful search functionalities including typo-tolerance, synonyms, filtering, and more. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [MeiliSearch instance](https://docs.meilisearch.com/learn/getting_started/quick_start.html#setup-and-installation) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-meilisearch + ``` + +2\. Set the following environment variables in `.env`: + + ```bash + MEILISEARCH_HOST= + MEILISEARCH_API_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-plugin-meilisearch`, + options: { + // config object passed when creating an instance + // of the MeiliSearch client + config: { + host: process.env.MEILISEARCH_HOST, + apiKey: process.env.MEILISEARCH_API_KEY, + }, + settings: { + // index name + products: { + // MeiliSearch's setting options + // to be set on a particular index + searchableAttributes: [ + "title", + "description", + "variant_sku", + ], + displayedAttributes: [ + "title", + "description", + "variant_sku", + "thumbnail", + "handle", + ], + }, + }, }, - primaryKey: "some_id" - transformer: (product: Product) => ({ id: product.id }) - } - } -} -``` + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Try searching products either using your storefront or using the [Store APIs](https://docs.medusajs.com/api/store#tag/Product/operation/PostProductsSearch). + +--- + +## Additional Resources + +- [MeiliSearch Plugin Documentation](https://docs.medusajs.com/plugins/search/meilisearch) diff --git a/packages/medusa-plugin-restock-notification/README.md b/packages/medusa-plugin-restock-notification/README.md index 8e0f336a38..e30444887d 100644 --- a/packages/medusa-plugin-restock-notification/README.md +++ b/packages/medusa-plugin-restock-notification/README.md @@ -1,89 +1,98 @@ -# medusa-plugin-restock-notification +# Restock Notifications +Send notifications to subscribed customers when an item has been restocked. -## Usage +[Medusa Website](https://medusajs.com/) | [Medusa Repository](https://github.com/medusajs/medusa) -Install the plugin: +## Features -`$ yarn add medusa-plugin-restock-notification` +- Triggers an event when a product variant has been restocked. +- Provides an endpoint to subscribe customers to receive restock notifications. +- Does not implement the email or notification sending mechanisms. Instead, it is compatible with Notification plugins such as [SendGrid](https://docs.medusajs.com/plugins/notifications/sendgrid). -```js -// medusa-config.js +--- -module.exports = { - ..., - plugins: [ - ..., - `medusa-plugin-restock-notification` +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Redis](https://docs.medusajs.com/development/backend/prepare-environment#redis) +- [PostgreSQL](https://docs.medusajs.com/development/backend/prepare-environment#postgresql) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-restock-notification + ``` + +2\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // other plugins... + { + resolve: `medusa-plugin-restock-notification`, + options: { + trigger_delay, // optional, delay time in milliseconds + inventory_required, // minimum inventory quantity to consider a variant as restocked + }, + }, ] -} -``` + ``` -The plugin will migrate your database to include the RestockNotification entity, which consists of a variant id of a sold out item and a jsonb list of arrays that wish to be notified about restocks for the item. +3\. Run the following command in the directory of the Medusa backend to run the plugin's migrations: + ```bash + medusa migrations run + ``` -## API endpoint +--- -The plugin exposes an endpoint to sign emails up for restock notifications: +## Test the Plugin -``` -POST /restock-notifications/variants/:variant_id +1\. Run the following command in the directory of the Medusa backend to run the backend: -Body + ```bash + npm run start + ``` + +2\. Subscribe an email or identification username (depends on your notification service) to receive restock notifications using the endpoint `/restock-notifications/variants/`. `` is the ID of the variant you're subscribing to. + +2\. Change the inventory quantity of a product variant based on the restock threshold you've set, and see the event `restock-notification.restocked` triggered. + +--- + +## Additional Information + +### API endpoint + +The plugin exposes an endpoint `/restock-notifications/variants/:variant_id` to sign emails up for restock notifications. It accepts the following request body: + +```json { - "email": "seb@test.com" + "email": "customer@test.com" } ``` The endpoint responds with `200 OK` on successful signups. If a signup for an already in stock item is attempted the endpoint will have a 400 response code. - -## Restock events +### Restock events The plugin listens for the `product-variant.updated` call and emits a `restock-notification.restocked` event when a variant with restock signups become available. -The data sent with the `restock-notification.restocked` event is: -``` -variant_id: The id of the variant to listen for restock events for. -emails: An array of emails that are to be notified of restocks. +The data sent with the `restock-notification.restocked` event are: -e.g. +- `variant_id`: The ID of the variant to listen for restock events for. +- `emails`: An array of emails that are to be notified of restocks. +For example: + +```json { "variant_id": "variant_1234567890", "emails": ["seb@test.com", "oli@test.com"] } ``` - -*Note: This plugin does not send any communication to the customer, communication logic must be implemented or provided through a communication plugin.* - -You may use `medusa-plugin-sendgrid` to orchestrate transactional emails. - - -## Usage with medusa-plugin-sendgrid - -Install the plugins: -`$ yarn add medusa-plugin-restock-notification medusa-plugin-sendgrid` - -```js -// medusa-config.js - -module.exports = { - ..., - plugins: [ - ..., - `medusa-plugin-restock-notification`, - { - resolve: `medusa-plugin-sendgrid`, - options: { - from: SENDGRID_FROM, - api_key: SENDGRID_API_KEY, - medusa_restock_template: `d-13141234123412342314` - } - } - ] -} -``` - -You should set up a dynamic template in SendGrid which will be send for each of the emails in the restock notification. - diff --git a/packages/medusa-plugin-segment/READMD.md b/packages/medusa-plugin-segment/READMD.md deleted file mode 100644 index 8c4bea6cf1..0000000000 --- a/packages/medusa-plugin-segment/READMD.md +++ /dev/null @@ -1,15 +0,0 @@ -# medusa-plugin-segment - -Segment Plugin to add tracking to your Medusa server. - -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/segment). - -## Options - -```js -{ - write_key: "" -} -``` - -Where `` is the write key of the Segment Source you create for the Medusa server. \ No newline at end of file diff --git a/packages/medusa-plugin-segment/README.md b/packages/medusa-plugin-segment/README.md new file mode 100644 index 0000000000..315ecdbbfa --- /dev/null +++ b/packages/medusa-plugin-segment/README.md @@ -0,0 +1,65 @@ +# Segment + +Track essential commerce analytics with Segment. + +[Segment Plugin Documentation](https://docs.medusajs.com/plugins/analytics/segment) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Automatic analytics tracking for events related to Orders, Swaps, and Claims. +- Flexibility to track analytics for custom events or operations. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Segment account](https://app.segment.com/signup) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-segment + ``` + +2\. Set the following environment variable in `.env`: + + ```bash + SEGMENT_WRITE_KEY= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-plugin-segment`, + options: { + write_key: process.env.SEGMENT_WRITE_KEY, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should see the event tracked in Segment. + +--- + +## Additional Resources + +- [Segment Plugin Documentation](https://docs.medusajs.com/plugins/analytics/segment) diff --git a/packages/medusa-plugin-sendgrid/README.md b/packages/medusa-plugin-sendgrid/README.md index 0c21577410..6cde3c5aff 100644 --- a/packages/medusa-plugin-sendgrid/README.md +++ b/packages/medusa-plugin-sendgrid/README.md @@ -1,47 +1,78 @@ -# medusa-plugin-sendgrid +# SendGrid -Sendgrid Plugin for Medusa to send transactional emails. +Handle sending emails to customers related to orders, restock notifications, users, or custom events. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/sendgrid). +[SendGrid Plugin Documentation](https://docs.medusajs.com/plugins/notifications/sendgrid) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -If no values are defined for a given option, the plugin will not try to send an email for that event. +- Send emails when an event related to orders, restock notifications, or users is triggered. +- Use dynamic templates in SendGrid to build the emails to be sent. +- Send emails with SendGrid for custom events. -```js -{ - api_key: "SENDGRID_API_KEY", //required - from: "[the from field, i.e. ACME ]", //required - gift_card_created_template: "[used on gift_card.created]", - order_placed_template: "[used on order.placed]", - order_canceled_template: "[used on order.canceled]", - order_shipped_template: "[used on order.shipment_created]", - order_completed_template: "[used on order.completed]", - user_password_reset_template: "[used on user.password_reset]", - customer_password_reset_template: "[used on customer.password_reset]", - localization: { - "de-DE": { // locale key - gift_card_created_template: "[used on gift_card.created]", - order_placed_template: "[used on order.placed]", - order_canceled_template: "[used on order.canceled]", - order_shipped_template: "[used on order.shipment_created]", - order_completed_template: "[used on order.completed]", - user_password_reset_template: "[used on user.password_reset]", - customer_password_reset_template: "[used on customer.password_reset]", - } - } -} -``` +--- -## Dynamic usage +## Prerequisites -You can resolve the SendGrid service to dynamically send emails via sendgrid. +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [SendGrid account](https://signup.sendgrid.com/) -Example: +--- -```js +## How to Install -const sendgridService = scope.resolve("sendgridService") -sendgridService.sendEmail("d-123....", "ACME ", "customer@mail.com", { dynamic: "data" }) +1\. Run the following command in the directory of the Medusa backend: -``` + ```bash + npm install medusa-plugin-sendgrid + ``` + +2\. Set the following environment variable in `.env`: + + ```bash + SENDGRID_API_KEY= + SENDGRID_FROM= + # IDs for different email templates + SENDGRID_ORDER_PLACED_ID= # example + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ..., + { + resolve: `medusa-plugin-sendgrid`, + options: { + api_key: process.env.SENDGRID_API_KEY, + from: process.env.SENDGRID_FROM, + order_placed_template: + process.env.SENDGRID_ORDER_PLACED_ID, + localization: { + "de-DE": { // locale key + order_placed_template: + process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED, + }, + }, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should receive a confirmation email. + +--- + +## Additional Resources + +- [SendGrid Plugin Documentation](https://docs.medusajs.com/plugins/notifications/sendgrid) diff --git a/packages/medusa-plugin-slack-notification/README.md b/packages/medusa-plugin-slack-notification/README.md index 49f824085e..64ef9268e3 100644 --- a/packages/medusa-plugin-slack-notification/README.md +++ b/packages/medusa-plugin-slack-notification/README.md @@ -1,15 +1,68 @@ -# medusa-plugin-slack-notification +# Slack -Slack Integration to receive new order notifications on Slack. +Receive new order notifications on Slack. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/slack). +[Slack Plugin Documentation](https://docs.medusajs.com/plugins/notifications/slack) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - show_discount_code: false, - slack_url: ``, - admin_orders_url: `http://localhost:7001/a/orders` -} -``` +- Receive details about new orders including purchased items, totals, customer information, and more. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Slack account](https://slack.com) +- [Redis](https://docs.medusajs.com/development/backend/prepare-environment#redis) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-slack-notification + ``` + +2\. Set the following environment variable in `.env`: + + ```bash + SLACK_WEBHOOK_URL= + SLACK_ADMIN_ORDERS_URL= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ..., + { + resolve: `medusa-plugin-slack-notification`, + options: { + show_discount_code: false, // optional, whether the discount code should be shown in notifications + slack_url: process.env.SLACK_WEBHOOK_URL, + admin_orders_url: process.env.SLACK_ADMIN_ORDERS_URL, // for example, http://localhost:7001/a/orders + }, + }, + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Place an order using a storefront or the [Store APIs](https://docs.medusajs.com/api/store). You should receive a notification on your Slack workspace. + +--- + +## Additional Resources + +- [Slack Plugin Documentation](https://docs.medusajs.com/plugins/notifications/slack) diff --git a/packages/medusa-plugin-twilio-sms/README.md b/packages/medusa-plugin-twilio-sms/README.md index eddbb828f8..be660416b6 100644 --- a/packages/medusa-plugin-twilio-sms/README.md +++ b/packages/medusa-plugin-twilio-sms/README.md @@ -1,26 +1,62 @@ -# medusa-plugin-twilio-sms +# Twilio SMS -Twilio SMS / Messaging plugin. +Utilize Twilio's SMS APIs to send customers SMS notifications. -Learn more about how you can use this plugin in the [documentaion](https://docs.medusajs.com/add-plugins/twilio-sms). +[Twilio SMS Plugin Documentation](https://docs.medusajs.com/plugins/notifications/twilio-sms) | [Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -## Options +## Features -```js -{ - account_sid: "[twilio messaging account sid]", // required - auth_token: "[twilio massaging authentication token]", // required - from_number: "[the number used as sender SMS]", -} -``` +- Access Twilio's SMS APIs easily using the `TwilioSmsService`. -## Dynamic usage +--- -You can resolve the Twilio SMS service to dynamically send SMS's via Twilio. +## Prerequisites -Example: +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Twilio account](https://www.twilio.com/sms) -```js -const twilioSmsService = scope.resolve("twilioSmsService") -twilioSmsService.sendSms({ to: "+4500112233", body: "Hello world!" }) -``` +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-twilio-sms + ``` + +2\. Set the following environment variable in `.env`: + + ```bash + TWILIO_SMS_ACCOUNT_SID= + TWILIO_SMS_AUTH_TOKEN= + TWILIO_SMS_FROM_NUMBER= + ``` + +3\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + { + resolve: `medusa-plugin-twilio-sms`, + options: { + account_sid: process.env.TWILIO_SMS_ACCOUNT_SID, + auth_token: process.env.TWILIO_SMS_AUTH_TOKEN, + from_number: process.env.TWILIO_SMS_FROM_NUMBER, + }, + }, + ] + ``` + +--- + +## Test the Plugin + +In your code, use the `TwilioSmsService` where necessary to send your customers notifications. + +--- + +## Additional Resources + +- [Twilio SMS Plugin Documentation](https://docs.medusajs.com/plugins/notifications/twilio-sms) diff --git a/packages/medusa-plugin-wishlist/README.md b/packages/medusa-plugin-wishlist/README.md new file mode 100644 index 0000000000..54aea1ac70 --- /dev/null +++ b/packages/medusa-plugin-wishlist/README.md @@ -0,0 +1,46 @@ +# Wishlist + +Add wishlist capabilities to your commerce application. + +[Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) + +## Features + +- Allow customers to manage items in their wishlist. + +--- + +## Prerequisites + +- [Medusa backend](https://docs.medusajs.com/development/backend/install) + +--- + +## How to Install + +1\. Run the following command in the directory of the Medusa backend: + + ```bash + npm install medusa-plugin-wishlist + ``` + +2\. In `medusa-config.js` add the following at the end of the `plugins` array: + + ```js + const plugins = [ + // ... + `medusa-plugin-wishlist` + ] + ``` + +--- + +## Test the Plugin + +1\. Run the following command in the directory of the Medusa backend to run the backend: + + ```bash + npm run start + ``` + +2\. Retrieve a customer's wishlist using the endpoint `/wishlist/:token`, where `:token` is the customer's token. diff --git a/packages/medusa-source-shopify/README.md b/packages/medusa-source-shopify/README.md index c0609b02e7..75dfc11f37 100644 --- a/packages/medusa-source-shopify/README.md +++ b/packages/medusa-source-shopify/README.md @@ -1,85 +1,61 @@ -# Medusa Source Shopify -Plugin that allows users to source Medusa using a Shopify store. +# Shopify Source -## Quick start +Migrate your products and categories from Shopify to Medusa. -This plugin will copy all of your products and collections from Shopify to Medusa. +[Medusa Website](https://medusajs.com) | [Medusa Repository](https://github.com/medusajs/medusa) -To get started with the plugin you should follow these steps. +## Features -### Install the plugin +- Migrate data related to products from Shopify to Medusa. +- Consistently keep data in sync between Shopify and Medusa. -Navigate to your Medusa server in your terminal, and install the plugin. +--- -```zsh -$ cd my-medusa-server -$ yarn medusa-source-shopify -``` +## Prerequisites -### Create a Shopify app +- [Medusa backend](https://docs.medusajs.com/development/backend/install) +- [Shopify account](https://shopify.dev/) -Navigate to your Shopify dashboard, and then go to `Apps` and click the `Develop apps for your store` button at the bottom of the page. After navigating to the `App development` page, click the `Create an app` in the top right corner. +--- -This should open a modal where you can choose a name for your app. Write a name and click `Create app`. +## How to Install -You should then click the button that says `Configure Admin API scopes`. Scroll down to `Products` and select the `read_products` scope, and then save your changes. +1\. Run the following command in the directory of the Medusa backend: -Go back to overview and click `Install app`. This should generate a token, that you should write down as you can only view it once. + ```bash + npm install medusa-source-shopify + ``` +2\. Set the following environment variable in `.env`: -### Add the required plugin options + ```bash + SHOPIFY_DOMAIN= + SHOPIFY_PASSWORD= + ``` -Update your `medusa-config.js` with the following: +3\. In `medusa-config.js` add the following at the end of the `plugins` array: -```js -//Shopify keys -const SHOPIFY_STORE_URL = process.env.SHOPIFY_STORE_URL || ""; -const SHOPIFY_API_KEY = process.env.SHOPIFY_API_KEY || ""; + ```js + const plugins = [ + // ..., + { + resolve: 'medusa-source-shopify', + options: { + domain: process.env.SHOPIFY_DOMAIN, + password: process.env.SHOPIFY_PASSWORD + } + } + ]; + ``` -const plugins = [ - // other plugins... - { - resolve: `medusa-source-shopify`, - options: { - domain: SHOPIFY_STORE_URL, - password: SHOPIFY_API_KEY, - }, - }, -]; -``` +--- -You should then add `SHOPIFY_STORE_URL` and `SHOPIFY_API_KEY` to your `.env`. - -```env -SHOPIFY_API_KEY= -SHOPIFY_STORE_URL= -``` - -The `SHOPIFY_API_KEY` is the token that we generated in the previous step. `SHOPIFY_STORE_URL` is the name of your store. You can view the name in the url of your Shopify dashboard, which has the following format `.myshopify.com`. - -### Run your server - -After setting everything up you can now run your server - -```zsh -$ yarn start -``` - -and the plugin will handle the rest. - -## Note - -### The plugin only queries updates since last build time - -The plugin stores everytime it is run, and will use this timestamp to only fetch products, collections and collects that have been updated in Shopify since the last time it pulled data. - -### `Product/Collection` relations (`Collect`) -Shopify supports products being part of more than one collection, but Medusa does not support this. For this reason a product will only be part of the first collection it has a relation to in Medusa. The plugin processes Shopify product/collection relations in the following order: - -1. Custom collections -2. Smart collections - -This means that if product `X` is part of custom collection `Y` and smart collection `Z` in Shopify, it will only be added to custom collection `X` in Medusa. +## Test the Plugin +1\. Run the following command in the directory of the Medusa backend to run the backend: + ```bash + npm run start + ``` +2\. The data migration runs on server start-up. You should see your Shopify products in Medusa. \ No newline at end of file diff --git a/packages/medusa-test-utils/CHANGELOG.md b/packages/medusa-test-utils/CHANGELOG.md index 500aea0906..aed89d73ab 100644 --- a/packages/medusa-test-utils/CHANGELOG.md +++ b/packages/medusa-test-utils/CHANGELOG.md @@ -9,6 +9,11 @@ - Plugin repository loader to work with Typeorm update - Updated dependencies [[`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73)]: - medusa-core-utils@1.2.0-rc.0 +## 1.1.40 + +### Patch Changes + +- [#3417](https://github.com/medusajs/medusa/pull/3417) [`fa4049cb5`](https://github.com/medusajs/medusa/commit/fa4049cb51232b2ed7091b1322c3fc14cd23e451) Thanks [@adrien2p](https://github.com/adrien2p)! - chores(medusa): Refactoring product update flow to improve handling and performances ## 1.1.39 diff --git a/packages/medusa-test-utils/src/mock-manager.js b/packages/medusa-test-utils/src/mock-manager.js index da30d5ec4d..4b7cf81674 100644 --- a/packages/medusa-test-utils/src/mock-manager.js +++ b/packages/medusa-test-utils/src/mock-manager.js @@ -1,11 +1,12 @@ export default { connection: { getMetadata: (target) => { - - return target["metadata"] ?? { - columns: [] - } - } + return ( + target["metadata"] ?? { + columns: [], + } + ) + }, }, getRepository: function (repo) { diff --git a/packages/medusa-test-utils/src/mock-repository.js b/packages/medusa-test-utils/src/mock-repository.js index 6a8abafb07..accefe207a 100644 --- a/packages/medusa-test-utils/src/mock-repository.js +++ b/packages/medusa-test-utils/src/mock-repository.js @@ -14,7 +14,7 @@ class MockRepo { del, count, insertBulk, - metadata + metadata, }) { this.create_ = create this.update_ = update @@ -31,7 +31,7 @@ class MockRepo { this.insertBulk_ = insertBulk this.metadata = metadata ?? { - columns: [] + columns: [], } } @@ -88,22 +88,11 @@ class MockRepo { return this.findDescendantsTree_(...args) } }) - findOneOrFail = jest.fn().mockImplementation((...args) => { - if (this.findOneOrFail_) { - return this.findOneOrFail_(...args) - } - }) - find = jest.fn().mockImplementation((...args) => { if (this.find_) { return this.find_(...args) } }) - softRemove = jest.fn().mockImplementation((...args) => { - if (this.softRemove_) { - return this.softRemove_(...args) - } - }) save = jest.fn().mockImplementation((...args) => { if (this.save_) { return this.save_(...args) diff --git a/packages/medusa/CHANGELOG.md b/packages/medusa/CHANGELOG.md index 7d0a61632d..00db017e7f 100644 --- a/packages/medusa/CHANGELOG.md +++ b/packages/medusa/CHANGELOG.md @@ -300,6 +300,24 @@ - @medusajs/utils@0.0.2-rc.0 - @medusajs/modules-sdk@0.1.0-rc.0 - @medusajs/medusa-cli@1.3.9-rc.0 +## 1.7.15 + +### Patch Changes + +- [#3539](https://github.com/medusajs/medusa/pull/3539) [`98fe8fd00`](https://github.com/medusajs/medusa/commit/98fe8fd00a1912fde1d2a93b434bda500a213c14) Thanks [@adrien2p](https://github.com/adrien2p)! - Fix(medusa): Variant update should include the id for the listeners to be able to identify the entity + +- [#3491](https://github.com/medusajs/medusa/pull/3491) [`2869763ea`](https://github.com/medusajs/medusa/commit/2869763ea9673cf5c5a3aa10b58f61b8e830ce21) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Fix eventBus.emit using redis mock + +## 1.7.14 + +### Patch Changes + +- [`902ed3c0b`](https://github.com/medusajs/medusa/commit/902ed3c0b21cd525d9975e59b7a8120ae5f7a895) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa): Issue with fixed total discount with tax-inclusive pricing enabled + +- [#3417](https://github.com/medusajs/medusa/pull/3417) [`fa4049cb5`](https://github.com/medusajs/medusa/commit/fa4049cb51232b2ed7091b1322c3fc14cd23e451) Thanks [@adrien2p](https://github.com/adrien2p)! - chores(medusa): Refactoring product update flow to improve handling and performances + +- Updated dependencies [[`fa4049cb5`](https://github.com/medusajs/medusa/commit/fa4049cb51232b2ed7091b1322c3fc14cd23e451)]: + - medusa-test-utils@1.1.40 ## 1.7.13 diff --git a/packages/medusa/src/api/middlewares/index.ts b/packages/medusa/src/api/middlewares/index.ts index 119626ac86..b693764952 100644 --- a/packages/medusa/src/api/middlewares/index.ts +++ b/packages/medusa/src/api/middlewares/index.ts @@ -4,16 +4,16 @@ import { default as wrap } from "./await-middleware" import { default as normalizeQuery } from "./normalized-query" import { default as requireCustomerAuthentication } from "./require-customer-authentication" -export { canAccessBatchJob } from "./batch-job/can-access-batch-job" -export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job" -export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount" -export { transformIncludesOptions } from "./transform-includes-options" -export { transformBody } from "./transform-body" export { default as authenticate } from "./authenticate" export { default as authenticateCustomer } from "./authenticate-customer" export { default as wrapHandler } from "./await-middleware" +export { canAccessBatchJob } from "./batch-job/can-access-batch-job" +export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job" +export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount" export { default as normalizeQuery } from "./normalized-query" export { default as requireCustomerAuthentication } from "./require-customer-authentication" +export { transformBody } from "./transform-body" +export { transformIncludesOptions } from "./transform-includes-options" export { transformQuery, transformStoreQuery } from "./transform-query" /** diff --git a/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts b/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts index 9d9300f0b5..05415259c0 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts @@ -25,6 +25,7 @@ import { AddressPayload } from "../../../../types/common" import { DraftOrderCreateProps } from "../../../../types/draft-orders" import { validator } from "../../../../utils/validator" import { IsType } from "../../../../utils/validators/is-type" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/draft-orders @@ -154,7 +155,7 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.status(200).json({ draft_order: draftOrder }) + res.status(200).json({ draft_order: cleanResponseData(draftOrder, []) }) } enum Status { diff --git a/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts b/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts index 2c674e4a19..e625890779 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts @@ -13,6 +13,7 @@ import { import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { validator } from "../../../../utils/validator" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/draft-orders/{id}/line-items @@ -138,7 +139,9 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.status(200).json({ draft_order: draftOrder }) + res.status(200).json({ + draft_order: cleanResponseData(draftOrder, []), + }) }) } diff --git a/packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts b/packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts index 73f58a9005..624c414489 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts @@ -8,6 +8,7 @@ import { import { DraftOrder } from "../../../.." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [delete] /admin/draft-orders/{id}/line-items/{line_id} @@ -93,6 +94,8 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.status(200).json({ draft_order: draftOrder }) + res.status(200).json({ + draft_order: cleanResponseData(draftOrder, []), + }) }) } diff --git a/packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts b/packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts index 50e50d12b3..da466dae02 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts @@ -7,6 +7,7 @@ import { } from "." import { DraftOrder } from "../../../.." +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [get] /admin/draft-orders/{id} @@ -77,5 +78,7 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.json({ draft_order: draftOrder }) + res.json({ + draft_order: cleanResponseData(draftOrder, []), + }) } diff --git a/packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts b/packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts index 8d8b4bb026..541d0e98e5 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts @@ -6,13 +6,14 @@ import { ProductVariantInventoryService, } from "../../../../services" +import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { Order } from "../../../../models" -import { MedusaError } from "medusa-core-utils" import { defaultAdminOrdersFields as defaultOrderFields, defaultAdminOrdersRelations as defaultOrderRelations, } from "../../../../types/orders" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/draft-orders/{id}/pay @@ -119,7 +120,7 @@ export default async (req, res) => { return order }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } export const reserveQuantityForDraftOrder = async ( diff --git a/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts b/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts index d8c1ba3c59..2102c96c60 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts @@ -19,6 +19,7 @@ import { CartUpdateProps } from "../../../../types/cart" import { AddressPayload } from "../../../../types/common" import { validator } from "../../../../utils/validator" import { IsType } from "../../../../utils/validators/is-type" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/draft-orders/{id} @@ -137,7 +138,7 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.status(200).json({ draft_order: draftOrder }) + res.status(200).json({ draft_order: cleanResponseData(draftOrder, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts b/packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts index d925d8a9d1..5fdce359f9 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts +++ b/packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts @@ -11,6 +11,7 @@ import { EntityManager } from "typeorm" import { LineItemUpdate } from "../../../../types/cart" import { MedusaError } from "medusa-core-utils" import { validator } from "../../../../utils/validator" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/draft-orders/{id}/line-items/{line_id} @@ -139,7 +140,9 @@ export default async (req, res) => { select: defaultAdminDraftOrdersCartFields, }) - res.status(200).json({ draft_order: draftOrder }) + res.status(200).json({ + draft_order: cleanResponseData(draftOrder, []), + }) }) } diff --git a/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts b/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts index 63a3d53c90..5a3067ddf2 100644 --- a/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts +++ b/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts @@ -9,6 +9,7 @@ import { import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/shipping-methods @@ -97,7 +98,7 @@ export default async (req, res) => { includes: req.includes, }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/archive-order.ts b/packages/medusa/src/api/routes/admin/orders/archive-order.ts index 812630af6f..0822d60e39 100644 --- a/packages/medusa/src/api/routes/admin/orders/archive-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/archive-order.ts @@ -1,6 +1,7 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/archive @@ -70,7 +71,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersOrderArchiveParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts b/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts index e5f74ec47d..2c7117a593 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts @@ -3,6 +3,7 @@ import { ClaimService, OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/claims/{claim_id}/cancel @@ -85,7 +86,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersClaimCancel extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts index 887c980bdd..5767d59b9f 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts @@ -7,6 +7,7 @@ import { import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/claims/{claim_id}/fulfillments/{fulfillment_id}/cancel @@ -101,7 +102,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersClaimFulfillmentsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts index 0118b04ba7..6dac90c092 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts @@ -7,6 +7,7 @@ import { import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/swaps/{swap_id}/fulfillments/{fulfillment_id}/cancel @@ -101,7 +102,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } // eslint-disable-next-line max-len diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts index 7b0642cc61..0bbc5de26b 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts @@ -9,6 +9,7 @@ import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { Fulfillment } from "../../../../models" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/fulfillments/{fulfillment_id}/cancel @@ -108,7 +109,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export const adjustInventoryForCancelledFulfillment = async ( diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts b/packages/medusa/src/api/routes/admin/orders/cancel-order.ts index da20a797b9..8672f2269e 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-order.ts @@ -1,6 +1,7 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/cancel @@ -69,7 +70,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersOrderCancel extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts b/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts index dd59d22bf1..25d90920a0 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts @@ -3,6 +3,7 @@ import { OrderService, SwapService } from "../../../../services" import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/swaps/{swap_id}/cancel @@ -83,7 +84,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersSwapCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/capture-payment.ts b/packages/medusa/src/api/routes/admin/orders/capture-payment.ts index a6b841b577..77af27bea4 100644 --- a/packages/medusa/src/api/routes/admin/orders/capture-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/capture-payment.ts @@ -1,6 +1,7 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/capture @@ -72,7 +73,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersOrderCaptureParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/complete-order.ts b/packages/medusa/src/api/routes/admin/orders/complete-order.ts index 73ff57b5bd..842a3e0e30 100644 --- a/packages/medusa/src/api/routes/admin/orders/complete-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/complete-order.ts @@ -1,6 +1,7 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/complete @@ -72,7 +73,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminPostOrdersOrderCompleteParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts index 80e99040f1..212d314f1f 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts @@ -2,6 +2,7 @@ import { ClaimService, OrderService } from "../../../../services" import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/claims/{claim_id}/shipments @@ -92,7 +93,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim.ts b/packages/medusa/src/api/routes/admin/orders/create-claim.ts index 4264111c85..ce108e0503 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-claim.ts @@ -16,6 +16,7 @@ import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { ClaimTypeValue } from "../../../../types/claim" import { AddressPayload, FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/claims @@ -254,7 +255,9 @@ export default async (req, res) => { return { response_code: 200, - response_body: { order }, + response_body: { + order, + }, } }) }) @@ -288,6 +291,13 @@ export default async (req, res) => { throw err } + if (idempotencyKey.response_body.order) { + idempotencyKey.response_body.order = cleanResponseData( + idempotencyKey.response_body.order, + [] + ) + } + res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) } diff --git a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts index 8351e7b926..7605a2bf53 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts @@ -18,6 +18,7 @@ import { import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" import { Fulfillment, LineItem } from "../../../../models" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/fulfillment @@ -150,7 +151,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } export const updateInventoryAndReservations = async ( diff --git a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-shipment.ts index 615fadfb6e..dc6e50ab51 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-shipment.ts @@ -10,6 +10,7 @@ import { EntityManager } from "typeorm" import { OrderService } from "../../../../services" import { TrackingLink } from "../../../../models" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/shipment @@ -104,7 +105,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts index 603f8f8407..d3967d9ac8 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts @@ -10,6 +10,7 @@ import { OrderService, SwapService } from "../../../../services" import { EntityManager } from "typeorm" import { validator } from "../../../../utils/validator" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/swaps/{swap_id}/shipments @@ -102,7 +103,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts index c5e8805144..c706ca76bf 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap.ts @@ -21,6 +21,7 @@ import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { Type } from "class-transformer" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/swaps @@ -219,7 +220,9 @@ export default async (req, res) => { return { response_code: 200, - response_body: { order }, + response_body: { + order: cleanResponseData(order, []), + }, } }) }) diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts index 43e8b83f96..5ba1255b9f 100644 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts @@ -1,12 +1,13 @@ +import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator" import { ClaimService, OrderService, ProductVariantInventoryService, } from "../../../../services" -import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" import { updateInventoryAndReservations } from "./create-fulfillment" /** @@ -128,7 +129,7 @@ export default async (req, res) => { includes: req.includes, }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts index 7d93afb21e..970dbc3083 100644 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts @@ -6,8 +6,9 @@ import { } from "../../../../services" import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" +import { validator } from "../../../../utils/validator" import { updateInventoryAndReservations } from "./create-fulfillment" /** @@ -134,7 +135,7 @@ export default async (req, res) => { includes: req.includes, }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/get-order.ts b/packages/medusa/src/api/routes/admin/orders/get-order.ts index 2b815f535a..d39e7ac194 100644 --- a/packages/medusa/src/api/routes/admin/orders/get-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/get-order.ts @@ -1,7 +1,7 @@ +import { Order } from "../../../../models" import { OrderService } from "../../../../services" import { FindParams } from "../../../../types/common" import { cleanResponseData } from "../../../../utils/clean-response-data" -import { Order } from "../../../../models" /** * @oas [get] /admin/orders/{id} @@ -72,7 +72,7 @@ export default async (req, res) => { order = cleanResponseData(order, req.allowedProperties) - res.json({ order: order }) + res.json({ order: cleanResponseData(order, []) }) } export class AdminGetOrdersOrderParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts index bed6c08c98..0e28ec739b 100644 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ b/packages/medusa/src/api/routes/admin/orders/index.ts @@ -98,7 +98,7 @@ export default (app, featureFlagRouter: FlagRouter) => { transformIncludesOptions(allowedOrderIncludes), transformQuery(AdminGetOrdersParams, { defaultRelations: relations, - defaultFields: defaultAdminOrdersFields, + defaultFields: defaultFields, isList: true, }), middlewares.wrap(require("./list-orders").default) diff --git a/packages/medusa/src/api/routes/admin/orders/list-orders.ts b/packages/medusa/src/api/routes/admin/orders/list-orders.ts index 1abc6abb73..a1ea9b358f 100644 --- a/packages/medusa/src/api/routes/admin/orders/list-orders.ts +++ b/packages/medusa/src/api/routes/admin/orders/list-orders.ts @@ -1,8 +1,8 @@ import { IsNumber, IsOptional, IsString } from "class-validator" -import { AdminListOrdersSelector } from "../../../../types/orders" -import { OrderService } from "../../../../services" import { Type } from "class-transformer" +import { OrderService } from "../../../../services" +import { AdminListOrdersSelector } from "../../../../types/orders" import { cleanResponseData } from "../../../../utils/clean-response-data" /** @@ -208,7 +208,12 @@ export default async (req, res) => { const data = cleanResponseData(orders, req.allowedProperties) - res.json({ orders: data, count, offset: skip, limit: take }) + res.json({ + orders: cleanResponseData(data, []), + count, + offset: skip, + limit: take, + }) } export class AdminGetOrdersParams extends AdminListOrdersSelector { diff --git a/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts b/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts index e912fcf33d..b3dba47355 100644 --- a/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts @@ -2,6 +2,7 @@ import { OrderService, SwapService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/swaps/{swap_id}/process-payment @@ -73,7 +74,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } // eslint-disable-next-line max-len diff --git a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts b/packages/medusa/src/api/routes/admin/orders/refund-payment.ts index beb99b1ca3..98a4315f34 100644 --- a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/refund-payment.ts @@ -9,6 +9,7 @@ import { import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/refund @@ -97,7 +98,7 @@ export default async (req, res) => { includes: req.includes, }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } /** 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 f38d4f356c..5c221ebe40 100644 --- a/packages/medusa/src/api/routes/admin/orders/request-return.ts +++ b/packages/medusa/src/api/routes/admin/orders/request-return.ts @@ -6,17 +6,18 @@ import { IsInt, IsOptional, IsString, - ValidateNested + ValidateNested, } from "class-validator" import { EntityManager } from "typeorm" import { Order, Return } from "../../../../models" import { EventBusService, OrderService, - ReturnService + ReturnService, } from "../../../../services" import { FindParams } from "../../../../types/common" import { OrdersReturnItem } from "../../../../types/orders" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/return @@ -241,7 +242,9 @@ export default async (req, res) => { return { response_code: 200, - response_body: { order }, + response_body: { + order: cleanResponseData(order, []), + }, } }) }) diff --git a/packages/medusa/src/api/routes/admin/orders/update-claim.ts b/packages/medusa/src/api/routes/admin/orders/update-claim.ts index fe357b8a6e..e07b01bf2d 100644 --- a/packages/medusa/src/api/routes/admin/orders/update-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/update-claim.ts @@ -14,6 +14,7 @@ import { Type } from "class-transformer" import { EntityManager } from "typeorm" import { validator } from "../../../../utils/validator" import { FindParams } from "../../../../types/common" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id}/claims/{claim_id} @@ -103,7 +104,7 @@ export default async (req, res) => { includes: req.includes, }) - res.json({ order: data }) + res.json({ order: cleanResponseData(data, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/orders/update-order.ts b/packages/medusa/src/api/routes/admin/orders/update-order.ts index c509451cc2..83db12cac3 100644 --- a/packages/medusa/src/api/routes/admin/orders/update-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/update-order.ts @@ -13,6 +13,7 @@ import { AddressPayload, FindParams } from "../../../../types/common" import { EntityManager } from "typeorm" import { OrderService } from "../../../../services" import { Type } from "class-transformer" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /admin/orders/{id} @@ -96,7 +97,7 @@ export default async (req, res) => { includes: req.includes, }) - res.status(200).json({ order }) + res.status(200).json({ order: cleanResponseData(order, []) }) } /** diff --git a/packages/medusa/src/api/routes/admin/products/update-product.ts b/packages/medusa/src/api/routes/admin/products/update-product.ts index aa093f60f9..076be1e562 100644 --- a/packages/medusa/src/api/routes/admin/products/update-product.ts +++ b/packages/medusa/src/api/routes/admin/products/update-product.ts @@ -18,6 +18,7 @@ import { EntityManager } from "typeorm" import { defaultAdminProductFields, defaultAdminProductRelations } from "." import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" import { ProductStatus, ProductVariant } from "../../../../models" +import { ProductVariantRepository } from "../../../../repositories/product-variant" import { PricingService, ProductService, @@ -39,7 +40,6 @@ import { import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" import { DistributedTransaction } from "../../../../utils/transaction" import { validator } from "../../../../utils/validator" -import { ProductVariantRepository } from "../../../../repositories/product-variant" import { createVariantTransaction, revertVariantTransaction, diff --git a/packages/medusa/src/api/routes/store/carts/add-shipping-method.ts b/packages/medusa/src/api/routes/store/carts/add-shipping-method.ts index 1d7d9eb313..07539a8cbf 100644 --- a/packages/medusa/src/api/routes/store/carts/add-shipping-method.ts +++ b/packages/medusa/src/api/routes/store/carts/add-shipping-method.ts @@ -3,7 +3,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/shipping-methods @@ -62,10 +62,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const validated = await validator( - StorePostCartsCartShippingMethodReq, - req.body - ) + const validated = req.validatedBody const manager: EntityManager = req.scope.resolve("manager") const cartService: CartService = req.scope.resolve("cartService") @@ -94,7 +91,7 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } /** diff --git a/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts b/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts index e151ede2bb..55f6b1c150 100644 --- a/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts +++ b/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts @@ -2,6 +2,7 @@ import { CartService, IdempotencyKeyService } from "../../../../services" import { EntityManager } from "typeorm" import { IdempotencyKey } from "../../../../models/idempotency-key" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/taxes @@ -118,5 +119,12 @@ export default async (req, res) => { throw err } + if (idempotencyKey.response_body.cart) { + idempotencyKey.response_body.cart = cleanResponseData( + idempotencyKey.response_body.cart, + [] + ) + } + res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) } diff --git a/packages/medusa/src/api/routes/store/carts/complete-cart.ts b/packages/medusa/src/api/routes/store/carts/complete-cart.ts index 54d17785b6..a7c21abb9e 100644 --- a/packages/medusa/src/api/routes/store/carts/complete-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/complete-cart.ts @@ -2,6 +2,7 @@ import { EntityManager } from "typeorm" import { AbstractCartCompletionStrategy } from "../../../../interfaces" import { IdempotencyKey } from "../../../../models" import { IdempotencyKeyService } from "../../../../services" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/complete @@ -90,5 +91,9 @@ export default async (req, res) => { req.request_context ) + if (response_body.data) { + response_body.data = cleanResponseData(response_body.data, []) + } + res.status(response_code).json(response_body) } 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 69bb7d19d9..6ba9d7fa87 100644 --- a/packages/medusa/src/api/routes/store/carts/create-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/create-cart.ts @@ -1,6 +1,3 @@ -import { EntityManager } from "typeorm" -import { isDefined, MedusaError } from "medusa-core-utils" -import reqIp from "request-ip" import { Type } from "class-transformer" import { IsArray, @@ -10,18 +7,22 @@ import { IsString, ValidateNested, } from "class-validator" +import { isDefined, MedusaError } from "medusa-core-utils" +import reqIp from "request-ip" +import { EntityManager } from "typeorm" +import { defaultStoreCartFields, defaultStoreCartRelations } from "." +import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" +import { Cart, LineItem } from "../../../../models" import { CartService, LineItemService, RegionService, } from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." -import { Cart, LineItem } from "../../../../models" +import { CartCreateProps } from "../../../../types/cart" +import { cleanResponseData } from "../../../../utils/clean-response-data" 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" /** * @oas [post] /store/carts @@ -172,7 +173,7 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart }) + res.status(200).json({ cart: cleanResponseData(cart, []) }) } export class Item { diff --git a/packages/medusa/src/api/routes/store/carts/create-line-item/index.ts b/packages/medusa/src/api/routes/store/carts/create-line-item/index.ts index 2a1caec0f9..cd18774c7e 100644 --- a/packages/medusa/src/api/routes/store/carts/create-line-item/index.ts +++ b/packages/medusa/src/api/routes/store/carts/create-line-item/index.ts @@ -11,6 +11,7 @@ import { runIdempotencyStep, RunIdempotencyStepOptions, } from "../../../../../utils/idempotency" +import { cleanResponseData } from "../../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/line-items @@ -130,6 +131,13 @@ export default async (req, res) => { throw err } + if (idempotencyKey.response_body.cart) { + idempotencyKey.response_body.cart = cleanResponseData( + idempotencyKey.response_body.cart, + [] + ) + } + res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) } diff --git a/packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts b/packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts index f8157dd3b2..6de27441fa 100644 --- a/packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts +++ b/packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts @@ -2,6 +2,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" import { EntityManager } from "typeorm" import IdempotencyKeyService from "../../../../services/idempotency-key" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/payment-sessions @@ -133,5 +134,11 @@ export default async (req, res) => { throw err } + if (idempotencyKey.response_body.cart) { + idempotencyKey.response_body.data = cleanResponseData( + idempotencyKey.response_body.cart, + [] + ) + } res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) } diff --git a/packages/medusa/src/api/routes/store/carts/delete-discount.ts b/packages/medusa/src/api/routes/store/carts/delete-discount.ts index 99f813b8af..a9382e00f0 100644 --- a/packages/medusa/src/api/routes/store/carts/delete-discount.ts +++ b/packages/medusa/src/api/routes/store/carts/delete-discount.ts @@ -1,6 +1,7 @@ import { EntityManager } from "typeorm" import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [delete] /store/carts/{id}/discounts/{code} @@ -71,5 +72,5 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } diff --git a/packages/medusa/src/api/routes/store/carts/delete-line-item.ts b/packages/medusa/src/api/routes/store/carts/delete-line-item.ts index 42ea3fed7b..36a0cbed58 100644 --- a/packages/medusa/src/api/routes/store/carts/delete-line-item.ts +++ b/packages/medusa/src/api/routes/store/carts/delete-line-item.ts @@ -1,6 +1,7 @@ import { EntityManager } from "typeorm" import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [delete] /store/carts/{id}/line-items/{line_id} @@ -72,5 +73,6 @@ export default async (req, res) => { select: defaultStoreCartFields, relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + + res.status(200).json({ cart: cleanResponseData(data, []) }) } diff --git a/packages/medusa/src/api/routes/store/carts/delete-payment-session.ts b/packages/medusa/src/api/routes/store/carts/delete-payment-session.ts index b9f529d5a8..3e363ef960 100644 --- a/packages/medusa/src/api/routes/store/carts/delete-payment-session.ts +++ b/packages/medusa/src/api/routes/store/carts/delete-payment-session.ts @@ -1,6 +1,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" import { EntityManager } from "typeorm" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [delete] /store/carts/{id}/payment-sessions/{provider_id} @@ -63,5 +64,5 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } diff --git a/packages/medusa/src/api/routes/store/carts/get-cart.ts b/packages/medusa/src/api/routes/store/carts/get-cart.ts index 52c3a22a62..82e64488cc 100644 --- a/packages/medusa/src/api/routes/store/carts/get-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/get-cart.ts @@ -1,5 +1,6 @@ import { CartService } from "../../../../services" import { EntityManager } from "typeorm" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [get] /store/carts/{id} @@ -70,5 +71,5 @@ export default async (req, res) => { } const data = await cartService.retrieveWithTotals(id, req.retrieveConfig) - res.json({ cart: data }) + res.json({ cart: cleanResponseData(data, []) }) } diff --git a/packages/medusa/src/api/routes/store/carts/index.ts b/packages/medusa/src/api/routes/store/carts/index.ts index 15938dfbe3..c443d69603 100644 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ b/packages/medusa/src/api/routes/store/carts/index.ts @@ -12,6 +12,10 @@ import { StorePostCartReq } from "./create-cart" import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params" import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param" +import { StorePostCartsCartShippingMethodReq } from "./add-shipping-method" +import { StorePostCartsCartPaymentSessionReq } from "./set-payment-session" +import { StorePostCartsCartLineItemsItemReq } from "./update-line-item" +import { StorePostCartsCartPaymentSessionUpdateReq } from "./update-payment-session" const route = Router() @@ -43,6 +47,11 @@ export default (app, container) => { const createMiddlewares = [ middlewareService.usePreCartCreation(), + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), transformBody(StorePostCartReq), extendRequestParams, validateSalesChannelParam, @@ -56,75 +65,149 @@ export default (app, container) => { route.post( "/:id", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), transformBody(StorePostCartsCartReq), middlewares.wrap(require("./update-cart").default) ) route.post( "/:id/complete", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./complete-cart").default) ) // DEPRECATION route.post( "/:id/complete-cart", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./complete-cart").default) ) // Line items route.post( "/:id/line-items", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./create-line-item").default) ) route.post( "/:id/line-items/:line_id", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), + transformBody(StorePostCartsCartLineItemsItemReq), middlewares.wrap(require("./update-line-item").default) ) route.delete( "/:id/line-items/:line_id", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./delete-line-item").default) ) route.delete( "/:id/discounts/:code", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./delete-discount").default) ) // Payment sessions route.post( "/:id/payment-sessions", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./create-payment-sessions").default) ) route.post( "/:id/payment-sessions/:provider_id", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), + transformBody(StorePostCartsCartPaymentSessionUpdateReq), middlewares.wrap(require("./update-payment-session").default) ) route.delete( "/:id/payment-sessions/:provider_id", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./delete-payment-session").default) ) route.post( "/:id/payment-sessions/:provider_id/refresh", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./refresh-payment-session").default) ) route.post( "/:id/payment-session", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), + transformBody(StorePostCartsCartPaymentSessionReq), middlewares.wrap(require("./set-payment-session").default) ) // Shipping Options route.post( "/:id/shipping-methods", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), + transformBody(StorePostCartsCartShippingMethodReq), middlewares.wrap(require("./add-shipping-method").default) ) // Taxes route.post( "/:id/taxes", + transformStoreQuery(FindParams, { + defaultRelations: defaultStoreCartRelations, + defaultFields: defaultStoreCartFields, + isList: false, + }), middlewares.wrap(require("./calculate-taxes").default) ) diff --git a/packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts b/packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts index 38a5a87f25..0e1252a4d2 100644 --- a/packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts +++ b/packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts @@ -1,5 +1,6 @@ import { CartService } from "../../../../services" import { EntityManager } from "typeorm" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/payment-sessions/{provider_id}/refresh @@ -67,5 +68,5 @@ export default async (req, res) => { ], }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } diff --git a/packages/medusa/src/api/routes/store/carts/set-payment-session.ts b/packages/medusa/src/api/routes/store/carts/set-payment-session.ts index e3a10aae33..a7b1282239 100644 --- a/packages/medusa/src/api/routes/store/carts/set-payment-session.ts +++ b/packages/medusa/src/api/routes/store/carts/set-payment-session.ts @@ -3,7 +3,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" import { EntityManager } from "typeorm" import { IsString } from "class-validator" -import { validator } from "../../../../utils/validator" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/payment-session @@ -62,10 +62,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const validated = await validator( - StorePostCartsCartPaymentSessionReq, - req.body - ) + const validated = req.validatedBody const cartService: CartService = req.scope.resolve("cartService") @@ -81,7 +78,7 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } /** diff --git a/packages/medusa/src/api/routes/store/carts/update-cart.ts b/packages/medusa/src/api/routes/store/carts/update-cart.ts index af9aaab19e..e397901ea8 100644 --- a/packages/medusa/src/api/routes/store/carts/update-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/update-cart.ts @@ -14,6 +14,7 @@ import { CartService } from "../../../../services" import { AddressPayload } from "../../../../types/common" import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" import { IsType } from "../../../../utils/validators/is-type" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id} @@ -100,7 +101,7 @@ export default async (req, res) => { select: defaultStoreCartFields, relations: defaultStoreCartRelations, }) - res.json({ cart: data }) + res.json({ cart: cleanResponseData(data, []) }) } class GiftCard { diff --git a/packages/medusa/src/api/routes/store/carts/update-line-item.ts b/packages/medusa/src/api/routes/store/carts/update-line-item.ts index 179d4685d2..c6a711a279 100644 --- a/packages/medusa/src/api/routes/store/carts/update-line-item.ts +++ b/packages/medusa/src/api/routes/store/carts/update-line-item.ts @@ -3,7 +3,7 @@ import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" -import { validator } from "../../../../utils/validator" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/line-items/{line_id} @@ -63,10 +63,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id, line_id } = req.params - const validated = await validator( - StorePostCartsCartLineItemsItemReq, - req.body - ) + const validated = req.validatedBody const manager: EntityManager = req.scope.resolve("manager") const cartService: CartService = req.scope.resolve("cartService") @@ -115,7 +112,7 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } /** diff --git a/packages/medusa/src/api/routes/store/carts/update-payment-session.ts b/packages/medusa/src/api/routes/store/carts/update-payment-session.ts index 398b5505b9..886e8cf4d7 100644 --- a/packages/medusa/src/api/routes/store/carts/update-payment-session.ts +++ b/packages/medusa/src/api/routes/store/carts/update-payment-session.ts @@ -1,8 +1,8 @@ import { IsObject } from "class-validator" import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" -import { validator } from "../../../../utils/validator" import { EntityManager } from "typeorm" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [post] /store/carts/{id}/payment-sessions/{provider_id} @@ -64,10 +64,7 @@ import { EntityManager } from "typeorm" export default async (req, res) => { const { id, provider_id } = req.params - const validated = await validator( - StorePostCartsCartPaymentSessionUpdateReq, - req.body - ) + const validated = req.validatedBody const cartService: CartService = req.scope.resolve("cartService") @@ -86,7 +83,7 @@ export default async (req, res) => { relations: defaultStoreCartRelations, }) - res.status(200).json({ cart: data }) + res.status(200).json({ cart: cleanResponseData(data, []) }) } /** diff --git a/packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts b/packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts index dec75fbce9..fb866958ea 100644 --- a/packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts +++ b/packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts @@ -1,6 +1,7 @@ import { defaultStoreOrdersFields, defaultStoreOrdersRelations } from "." import { OrderService } from "../../../../services" +import { cleanResponseData } from "../../../../utils/clean-response-data" /** * @oas [get] /store/orders/cart/{cart_id} @@ -54,5 +55,5 @@ export default async (req, res) => { relations: defaultStoreOrdersRelations, }) - res.json({ order }) + res.json({ order: cleanResponseData(order, []) }) } diff --git a/packages/medusa/src/api/routes/store/orders/index.ts b/packages/medusa/src/api/routes/store/orders/index.ts index 26e78ce41c..adb510e744 100644 --- a/packages/medusa/src/api/routes/store/orders/index.ts +++ b/packages/medusa/src/api/routes/store/orders/index.ts @@ -10,6 +10,7 @@ import { StorePostCustomersCustomerOrderClaimReq } from "./request-order" import { StorePostCustomersCustomerAcceptClaimReq } from "./confirm-order-request" import { StoreGetOrderParams } from "./get-order" import { StoreGetOrdersParams } from "./lookup-order" +import { FindParams } from "../../../../types/common" const route = Router() @@ -50,6 +51,12 @@ export default (app) => { */ route.get( "/cart/:cart_id", + transformStoreQuery(FindParams, { + defaultFields: defaultStoreOrdersFields, + defaultRelations: defaultStoreOrdersRelations, + allowedFields: allowedStoreOrdersFields, + allowedRelations: allowedStoreOrdersRelations, + }), middlewares.wrap(require("./get-order-by-cart").default) ) diff --git a/packages/medusa/src/api/routes/store/product-categories/index.ts b/packages/medusa/src/api/routes/store/product-categories/index.ts index 3abac1838a..11474746cc 100644 --- a/packages/medusa/src/api/routes/store/product-categories/index.ts +++ b/packages/medusa/src/api/routes/store/product-categories/index.ts @@ -1,7 +1,7 @@ import { Router } from "express" -import middlewares, { transformStoreQuery } from "../../../middlewares" import { ProductCategory } from "../../../../models" import { PaginatedResponse } from "../../../../types/common" +import middlewares, { transformStoreQuery } from "../../../middlewares" import listProductCategories, { StoreGetProductCategoriesParams, diff --git a/packages/medusa/src/api/routes/store/products/index.ts b/packages/medusa/src/api/routes/store/products/index.ts index 7d10aed953..d6d84dc6bd 100644 --- a/packages/medusa/src/api/routes/store/products/index.ts +++ b/packages/medusa/src/api/routes/store/products/index.ts @@ -2,14 +2,14 @@ import { Router } from "express" import "reflect-metadata" import { Product } from "../../../.." -import middlewares, { transformStoreQuery } from "../../../middlewares" import { PaginatedResponse } from "../../../../types/common" +import { FlagRouter } from "../../../../utils/flag-router" +import middlewares, { transformStoreQuery } from "../../../middlewares" import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params" import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association" import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param" -import { StoreGetProductsParams } from "./list-products" import { StoreGetProductsProductParams } from "./get-product" -import { FlagRouter } from "../../../../utils/flag-router" +import { StoreGetProductsParams } from "./list-products" const route = Router() diff --git a/packages/medusa/src/helpers/test-request.js b/packages/medusa/src/helpers/test-request.js index a05a2679bf..2e50f54626 100644 --- a/packages/medusa/src/helpers/test-request.js +++ b/packages/medusa/src/helpers/test-request.js @@ -1,3 +1,8 @@ +import { + moduleHelper, + moduleLoader, + registerModules, +} from "@medusajs/modules-sdk" import { asValue, createContainer } from "awilix" import express from "express" import jwt from "jsonwebtoken" @@ -7,16 +12,11 @@ import "reflect-metadata" import supertest from "supertest" import apiLoader from "../loaders/api" import featureFlagLoader, { featureFlagRouter } from "../loaders/feature-flags" +import models from "../loaders/models" import passportLoader from "../loaders/passport" +import repositories from "../loaders/repositories" import servicesLoader from "../loaders/services" import strategiesLoader from "../loaders/strategies" -import { - moduleHelper, - moduleLoader, - registerModules, -} from "@medusajs/modules-sdk" -import repositories from "../loaders/repositories" -import models from "../loaders/models" const adminSessionOpts = { cookieName: "session", diff --git a/packages/medusa/src/interfaces/cart-completion-strategy.ts b/packages/medusa/src/interfaces/cart-completion-strategy.ts index 933c569ff1..c0ed22d8e3 100644 --- a/packages/medusa/src/interfaces/cart-completion-strategy.ts +++ b/packages/medusa/src/interfaces/cart-completion-strategy.ts @@ -1,13 +1,13 @@ +import { TransactionBaseService } from "@medusajs/utils" import { IdempotencyKey } from "../models" import { RequestContext } from "../types/request" -import { TransactionBaseService } from "./transaction-base-service" export type CartCompletionResponse = { /** The response code for the completion request */ response_code: number /** The response body for the completion request */ - response_body: object + response_body: Record } export interface ICartCompletionStrategy { diff --git a/packages/medusa/src/migrations/1678093365812-line-item-adjustments-amount.ts b/packages/medusa/src/migrations/1678093365812-line-item-adjustments-amount.ts new file mode 100644 index 0000000000..93ed4bd95c --- /dev/null +++ b/packages/medusa/src/migrations/1678093365812-line-item-adjustments-amount.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class lineItemAdjustmentsAmount1678093365812 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE line_item_adjustment ALTER COLUMN amount TYPE NUMERIC; + `) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE line_item_adjustment ALTER COLUMN amount TYPE integer; + `) + } +} diff --git a/packages/medusa/src/models/cart.ts b/packages/medusa/src/models/cart.ts index 026d820c96..0b83563ed9 100644 --- a/packages/medusa/src/models/cart.ts +++ b/packages/medusa/src/models/cart.ts @@ -170,6 +170,10 @@ * type: integer * example: 1000 * discount_total: + * description: The total of discount rounded + * type: integer + * example: 800 + * raw_discount_total: * description: The total of discount * type: integer * example: 800 @@ -376,6 +380,7 @@ export class Cart extends SoftDeletableEntity { shipping_total?: number discount_total?: number + raw_discount_total?: number item_tax_total?: number | null shipping_tax_total?: number | null tax_total?: number | null diff --git a/packages/medusa/src/models/line-item-adjustment.ts b/packages/medusa/src/models/line-item-adjustment.ts index 8a4f2edd43..af0245dc8b 100644 --- a/packages/medusa/src/models/line-item-adjustment.ts +++ b/packages/medusa/src/models/line-item-adjustment.ts @@ -8,10 +8,9 @@ import { PrimaryColumn, } from "typeorm" -import { DbAwareColumn } from "../utils/db-aware-column" +import { DbAwareColumn, generateEntityId } from "../utils" import { Discount } from "./discount" import { LineItem } from "./line-item" -import { generateEntityId } from "../utils/generate-entity-id" @Entity() @Index(["discount_id", "item_id"], { @@ -41,7 +40,7 @@ export class LineItemAdjustment { @Column({ nullable: true }) discount_id: string - @Column({ type: "int" }) + @Column({ type: "numeric", transformer: { to: (value) => value, from: (value) => parseFloat(value) } }) amount: number @DbAwareColumn({ type: "jsonb", nullable: true }) @@ -93,7 +92,7 @@ export class LineItemAdjustment { * $ref: "#/components/schemas/Discount" * amount: * description: The adjustment amount - * type: integer + * type: number * example: 1000 * metadata: * description: An optional key-value map with additional details diff --git a/packages/medusa/src/models/line-item.ts b/packages/medusa/src/models/line-item.ts index 8e39cf34df..34d3c5ea21 100644 --- a/packages/medusa/src/models/line-item.ts +++ b/packages/medusa/src/models/line-item.ts @@ -10,7 +10,8 @@ import { } from "typeorm" import { BaseEntity } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" +import TaxInclusivePricingFeatureFlag + from "../loaders/feature-flags/tax-inclusive-pricing" import { generateEntityId } from "../utils" import { DbAwareColumn } from "../utils/db-aware-column" import { FeatureFlagColumn } from "../utils/feature-flag-decorators" @@ -147,6 +148,7 @@ export class LineItem extends BaseEntity { original_total?: number | null original_tax_total?: number | null discount_total?: number | null + raw_discount_total?: number | null gift_card_total?: number | null @BeforeInsert() @@ -341,6 +343,10 @@ export class LineItem extends BaseEntity { * type: integer * example: 0 * discount_total: + * description: The total of discount of the line item rounded + * type: integer + * example: 0 + * raw_discount_total: * description: The total of discount of the line item * type: integer * example: 0 diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts index 19c17eb066..2d6f8c0a6b 100644 --- a/packages/medusa/src/models/order.ts +++ b/packages/medusa/src/models/order.ts @@ -241,6 +241,7 @@ export class Order extends BaseEntity { // Total fields shipping_total: number discount_total: number + raw_discount_total: number tax_total: number | null refunded_total: number total: number @@ -506,10 +507,14 @@ export class Order extends BaseEntity { * type: integer * description: The total of shipping * example: 1000 - * discount_total: + * raw_discount_total: * description: The total of discount * type: integer * example: 800 + * discount_total: + * description: The total of discount rounded + * type: integer + * example: 800 * tax_total: * description: The total of tax * type: integer diff --git a/packages/medusa/src/repositories/image.ts b/packages/medusa/src/repositories/image.ts index 274544d829..e1393092d5 100644 --- a/packages/medusa/src/repositories/image.ts +++ b/packages/medusa/src/repositories/image.ts @@ -1,8 +1,8 @@ import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { Image } from "../models" -import { dataSource } from "../loaders/database" import { In } from "typeorm" +import { dataSource } from "../loaders/database" +import { Image } from "../models" export const ImageRepository = dataSource.getRepository(Image).extend({ async insertBulk(data: QueryDeepPartialEntity[]): Promise { diff --git a/packages/medusa/src/repositories/money-amount.ts b/packages/medusa/src/repositories/money-amount.ts index 558b241f7f..65cbfcb308 100644 --- a/packages/medusa/src/repositories/money-amount.ts +++ b/packages/medusa/src/repositories/money-amount.ts @@ -8,12 +8,12 @@ import { WhereExpressionBuilder, } from "typeorm" import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" +import { dataSource } from "../loaders/database" import { MoneyAmount } from "../models" import { PriceListPriceCreateInput, PriceListPriceUpdateInput, } from "../types/price-list" -import { dataSource } from "../loaders/database" import { ProductVariantPrice } from "../types/product-variant" import { isString } from "../utils" diff --git a/packages/medusa/src/repositories/staged-job.ts b/packages/medusa/src/repositories/staged-job.ts index fccc053809..ad3159df4a 100644 --- a/packages/medusa/src/repositories/staged-job.ts +++ b/packages/medusa/src/repositories/staged-job.ts @@ -19,4 +19,5 @@ export const StagedJobRepository = dataSource.getRepository(StagedJob).extend({ return rawStagedJobs.generatedMaps.map((d) => this.create(d)) }, }) + export default StagedJobRepository diff --git a/packages/medusa/src/services/__tests__/discount.js b/packages/medusa/src/services/__tests__/discount.js index 8782c77a69..03378f61ee 100644 --- a/packages/medusa/src/services/__tests__/discount.js +++ b/packages/medusa/src/services/__tests__/discount.js @@ -737,8 +737,9 @@ describe("DiscountService", () => { } ) - expect(adjustment1).toBe(291) - expect(adjustment2).toBe(109) + // The sum of both is equal to the expected 400 + expect(adjustment1).toBeCloseTo(291, 0) + expect(adjustment2).toBeCloseTo(109, 0) }) it("returns line item amount if discount exceeds lime item price", async () => { diff --git a/packages/medusa/src/services/__tests__/order.js b/packages/medusa/src/services/__tests__/order.js index e23460eb3c..186f1f1273 100644 --- a/packages/medusa/src/services/__tests__/order.js +++ b/packages/medusa/src/services/__tests__/order.js @@ -1349,6 +1349,7 @@ describe("OrderService", () => { id: IdMap.getId("order"), items: [], paid_total: 0, + raw_discount_total: 0, refundable_amount: 0, refunded_total: 0, shipping_methods: [ @@ -1388,6 +1389,7 @@ describe("OrderService", () => { id: IdMap.getId("order"), items: [], paid_total: 0, + raw_discount_total: 0, refundable_amount: 0, refunded_total: 0, shipping_methods: [ diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index e6cccf0282..39250ac7b6 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -2600,7 +2600,7 @@ class CartService extends TransactionBaseService { const itemWithTotals = Object.assign(item, itemsTotals[item.id] ?? {}) cart.subtotal! += itemWithTotals.subtotal ?? 0 - cart.discount_total! += itemWithTotals.discount_total ?? 0 + cart.discount_total! += itemWithTotals.raw_discount_total ?? 0 cart.item_tax_total! += itemWithTotals.tax_total ?? 0 return itemWithTotals @@ -2627,11 +2627,15 @@ class CartService extends TransactionBaseService { giftCards: cart.gift_cards, } ) + cart.gift_card_total = giftCardTotal.total || 0 cart.gift_card_tax_total = giftCardTotal.tax_total || 0 cart.tax_total = cart.item_tax_total + cart.shipping_tax_total + cart.raw_discount_total = cart.discount_total + cart.discount_total = Math.round(cart.discount_total) + cart.total = cart.subtotal + cart.shipping_total + diff --git a/packages/medusa/src/services/discount.ts b/packages/medusa/src/services/discount.ts index 9d9b32b594..1cf6e75e68 100644 --- a/packages/medusa/src/services/discount.ts +++ b/packages/medusa/src/services/discount.ts @@ -619,7 +619,10 @@ class DiscountService extends TransactionBaseService { }) let fullItemPrice = lineItem.unit_price * lineItem.quantity - const includesTax = this.featureFlagRouter_.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key) && lineItem.includes_tax + const includesTax = + this.featureFlagRouter_.isFeatureEnabled( + TaxInclusivePricingFeatureFlag.key + ) && lineItem.includes_tax if (includesTax) { const lineItemTotals = await this.newTotalsService_ @@ -656,14 +659,13 @@ class DiscountService extends TransactionBaseService { }, 0) const nominator = Math.min(value, subtotal) const totalItemPercentage = fullItemPrice / subtotal - adjustment = Math.round(nominator * totalItemPercentage) + + adjustment = nominator * totalItemPercentage } else { adjustment = value * lineItem.quantity } - // if the amount of the discount exceeds the total price of the item, - // we return the total item price, else the fixed amount - return adjustment >= fullItemPrice ? fullItemPrice : adjustment + return Math.min(adjustment, fullItemPrice) }) } diff --git a/packages/medusa/src/services/new-totals.ts b/packages/medusa/src/services/new-totals.ts index d509b29058..0f593db3cb 100644 --- a/packages/medusa/src/services/new-totals.ts +++ b/packages/medusa/src/services/new-totals.ts @@ -31,6 +31,8 @@ type LineItemTotals = { original_tax_total: number tax_lines: LineItemTaxLine[] discount_total: number + + raw_discount_total: number } type GiftCardTransaction = { @@ -166,7 +168,8 @@ export default class NewTotalsService extends TransactionBaseService { subtotal = 0 // in that case we need to know the tax rate to compute it later } - const discount_total = lineItemAllocation.discount?.amount ?? 0 + const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 + const discount_total = Math.round(raw_discount_total) const totals: LineItemTotals = { unit_price: item.unit_price, @@ -178,6 +181,8 @@ export default class NewTotalsService extends TransactionBaseService { original_tax_total: 0, tax_total: 0, tax_lines: item.tax_lines ?? [], + + raw_discount_total: raw_discount_total, } if (includeTax) { @@ -268,7 +273,8 @@ export default class NewTotalsService extends TransactionBaseService { subtotal = 0 // in that case we need to know the tax rate to compute it later } - const discount_total = lineItemAllocation.discount?.amount ?? 0 + const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 + const discount_total = Math.round(raw_discount_total) const totals: LineItemTotals = { unit_price: item.unit_price, @@ -280,6 +286,8 @@ export default class NewTotalsService extends TransactionBaseService { original_tax_total: 0, tax_total: 0, tax_lines: [], + + raw_discount_total, } taxRate = taxRate / 100 diff --git a/packages/medusa/src/services/order.ts b/packages/medusa/src/services/order.ts index 3b823205a5..fb30b6ccd9 100644 --- a/packages/medusa/src/services/order.ts +++ b/packages/medusa/src/services/order.ts @@ -1842,6 +1842,7 @@ class OrderService extends TransactionBaseService { order.paid_total = order.payments?.reduce((acc, next) => (acc += next.amount), 0) || 0 order.refundable_amount = order.paid_total - order.refunded_total || 0 + let item_tax_total = 0 let shipping_tax_total = 0 @@ -1855,7 +1856,7 @@ class OrderService extends TransactionBaseService { Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) order.subtotal += item.subtotal ?? 0 - order.discount_total += item.discount_total ?? 0 + order.discount_total += item.raw_discount_total ?? 0 item_tax_total += item.tax_total ?? 0 if (isReturnableItem(item)) { @@ -1929,6 +1930,9 @@ class OrderService extends TransactionBaseService { }) } + order.raw_discount_total = order.discount_total + order.discount_total = Math.round(order.discount_total) + order.total = order.subtotal + order.shipping_total + diff --git a/packages/medusa/src/services/product-variant.ts b/packages/medusa/src/services/product-variant.ts index 265d8e7b9e..fce38d8cd2 100644 --- a/packages/medusa/src/services/product-variant.ts +++ b/packages/medusa/src/services/product-variant.ts @@ -47,13 +47,13 @@ import { setMetadata, } from "../utils" +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" import { CartRepository } from "../repositories/cart" import { MoneyAmountRepository } from "../repositories/money-amount" import { ProductRepository } from "../repositories/product" import { ProductOptionValueRepository } from "../repositories/product-option-value" import EventBusService from "./event-bus" import RegionService from "./region" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" class ProductVariantService extends TransactionBaseService { static Events = { diff --git a/packages/medusa/src/services/product.ts b/packages/medusa/src/services/product.ts index 0a0f16f27a..9c6cae9074 100644 --- a/packages/medusa/src/services/product.ts +++ b/packages/medusa/src/services/product.ts @@ -473,9 +473,6 @@ class ProductService extends TransactionBaseService { ): Promise { return await this.atomicPhase_(async (manager) => { const productRepo = manager.withRepository(this.productRepository_) - const productVariantRepo = manager.withRepository( - this.productVariantRepository_ - ) const productTagRepo = manager.withRepository(this.productTagRepository_) const productTypeRepo = manager.withRepository( this.productTypeRepository_ diff --git a/packages/medusa/src/services/totals.ts b/packages/medusa/src/services/totals.ts index e4991e94c5..1dd74b4545 100644 --- a/packages/medusa/src/services/totals.ts +++ b/packages/medusa/src/services/totals.ts @@ -58,6 +58,8 @@ type LineItemTotals = { original_tax_total: number tax_lines: LineItemTaxLine[] discount_total: number + + raw_discount_total: number } type LineItemTotalsOptions = { @@ -460,7 +462,7 @@ class TotalsService extends TransactionBaseService { /** * Used for the refund computation */ - unit_amount: Math.round(adjustmentAmount / ld.item.quantity), + unit_amount: adjustmentAmount / ld.item.quantity, } } else { allocationMap[ld.item.id] = { @@ -795,7 +797,8 @@ class TotalsService extends TransactionBaseService { subtotal = 0 // in that case we need to know the tax rate to compute it later } - const discount_total = lineItemAllocation.discount?.amount ?? 0 + const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 + const discount_total = Math.round(raw_discount_total) const lineItemTotals: LineItemTotals = { unit_price: lineItem.unit_price, @@ -807,6 +810,8 @@ class TotalsService extends TransactionBaseService { original_tax_total: 0, tax_total: 0, tax_lines: lineItem.tax_lines || [], + + raw_discount_total, } // Tax Information @@ -1002,7 +1007,9 @@ class TotalsService extends TransactionBaseService { excludeNonDiscounts: true, }) - const discountTotal = this.getLineItemAdjustmentsTotal(cartOrOrder) + const discountTotal = Math.round( + this.getLineItemAdjustmentsTotal(cartOrOrder) + ) if (subtotal < 0) { return this.rounded(Math.max(subtotal, discountTotal)) diff --git a/packages/medusa/src/utils/__tests__/omit-deep.spec.ts b/packages/medusa/src/utils/__tests__/omit-deep.spec.ts new file mode 100644 index 0000000000..53dd214b9c --- /dev/null +++ b/packages/medusa/src/utils/__tests__/omit-deep.spec.ts @@ -0,0 +1,59 @@ +import { omitDeep } from "../omit-deep" + +describe("omitDeep", () => { + it("should omit properties in a nested object", () => { + const input = { + id: 1, + __typename: "123", + createdAt: "1020209", + address: { + id: 1, + __typename: "123", + }, + variants: [ + 20, + { + id: 22, + title: "hello world", + __typename: "123", + createdAt: "1020209", + variantOption: { + id: 1, + __typename: "123", + }, + }, + { + id: 32, + test: null, + __typename: "123", + createdAt: "1020209", + }, + ], + } + + const output = { + id: 1, + address: { + id: 1, + }, + variants: [ + 20, + { + id: 22, + title: "hello world", + variantOption: { + id: 1, + }, + }, + { + id: 32, + test: null, + }, + ], + } + + expect( + omitDeep(input, ["createdAt", "updatedAt", "__typename"]) + ).toEqual(output) + }) +}) \ No newline at end of file diff --git a/packages/medusa/src/utils/clean-response-data.ts b/packages/medusa/src/utils/clean-response-data.ts index 44028413ef..b9ce0f4454 100644 --- a/packages/medusa/src/utils/clean-response-data.ts +++ b/packages/medusa/src/utils/clean-response-data.ts @@ -1,10 +1,11 @@ import { pick } from "lodash" +import { omitDeep } from "./omit-deep" // TODO: once the legacy totals decoration will be removed. // We will be able to only compute the totals if one of the total fields is present // and therefore avoid totals computation if the user don't want them to appear in the response // and therefore the below const will be removed -const EXCLUDED_FIELDS = [ +const INCLUDED_FIELDS = [ "shipping_total", "discount_total", "tax_total", @@ -22,6 +23,8 @@ const EXCLUDED_FIELDS = [ "original_tax_total", ] +const EXCLUDED_FIELDS = ["raw_discount_total"] + /** * Filter response data to contain props specified in the `allowedProperties`. * You can read more in the transformQuery middleware utility methods. @@ -33,17 +36,25 @@ function cleanResponseData( data: T, fields: string[] ): T extends [] ? Partial[] : Partial { - if (!fields.length) { - return data as T extends [] ? Partial[] : Partial - } + fields = fields ?? [] const isDataArray = Array.isArray(data) - const fieldsSet = new Set([...fields, ...EXCLUDED_FIELDS]) + let arrayData: Partial[] = isDataArray ? data : [data] + + if (!fields.length) { + arrayData = arrayData.map((record) => omitDeep(record, EXCLUDED_FIELDS)) + return (isDataArray ? arrayData : arrayData[0]) as T extends [] + ? Partial[] + : Partial + } + + const fieldsSet = new Set([...fields, ...INCLUDED_FIELDS]) fields = [...fieldsSet] - let arrayData: Partial[] = isDataArray ? data : [data] - arrayData = arrayData.map((record) => pick(record, fields)) + arrayData = arrayData.map((record) => + pick(omitDeep(record, EXCLUDED_FIELDS), fields) + ) return (isDataArray ? arrayData : arrayData[0]) as T extends [] ? Partial[] diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index d8f7e0312e..ed84e7a9d0 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -4,12 +4,12 @@ export * from "./csv-cell-content-formatter" export * from "./db-aware-column" export * from "./exception-formatter" export * from "./generate-entity-id" +export * from "./has-changes" export * from "./is-date" export * from "./is-object" export * from "./is-string" +export * from "./omit-deep" export * from "./product-category" export * from "./remove-undefined-properties" export * from "./set-metadata" export * from "./validate-id" -export * from "./is-object" -export * from "./has-changes" diff --git a/packages/medusa/src/utils/is-object.ts b/packages/medusa/src/utils/is-object.ts index 778a601412..e577671adc 100644 --- a/packages/medusa/src/utils/is-object.ts +++ b/packages/medusa/src/utils/is-object.ts @@ -1,3 +1,3 @@ -export function isObject(obj: unknown): obj is object { - return typeof obj === "object" && !!obj +export function isObject(obj: any): obj is object { + return obj != null && obj?.constructor?.name === "Object" } diff --git a/packages/medusa/src/utils/omit-deep.ts b/packages/medusa/src/utils/omit-deep.ts new file mode 100644 index 0000000000..a86453c0a7 --- /dev/null +++ b/packages/medusa/src/utils/omit-deep.ts @@ -0,0 +1,34 @@ +import { isObject } from "./is-object" + +export function omitDeep( + input: object, + excludes: Array +): T { + if (!input) { + return input + } + + return Object.entries(input).reduce((nextInput, [key, value]) => { + const shouldExclude = excludes.includes(key) + if (shouldExclude) { + return nextInput + } + + if (Array.isArray(value)) { + nextInput[key] = value.map((arrItem) => { + if (isObject(arrItem)) { + return omitDeep(arrItem, excludes) + } + return arrItem + }) + return nextInput + } else if (isObject(value)) { + nextInput[key] = omitDeep(value, excludes) + return nextInput + } + + nextInput[key] = value + + return nextInput + }, {} as T) +}